属性描述符初探——Vue实现数据劫持的基础

简介: 属性描述符还有很多内容可以挖掘,比如defineProperty与Proxy的区别,比如vue2与vue3实现数据劫持的方式有什么不同,实现效果有哪些差异等,这篇博文只是入门,以后有时间再深挖。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~


       请注意,本文讲述的是JS中的属性描述符,不是Python中的属性描述符

属性描述符——Vue实现数据劫持的基础

image.gif 编辑

一、属性描述符是什么?

       属性描述符(Property Descriptor)在JavaScript中是一个特殊的对象,它定义了对象属性的行为和特性。

       属性描述符是一个对象,它通常包含以下几个属性:

  • value:属性的值。这是一个数据属性的特性,用于存储属性值。
  • writable:一个布尔值,表示属性的值是否可被修改。如果设置为false,属性值将不可修改。
  • get:一个函数,当访问属性时调用,用于获取属性值。这是一个访问器属性的特性。
  • set:一个函数,当设置属性值时调用,用于设置属性值。这是一个访问器属性的特性。
  • enumerable:一个布尔值,表示属性是否可被枚举,默认为false。如果设置为true,则属性会显示在for-in循环和Object.keys()的结果中。
  • configurable:一个布尔值,表示属性的属性描述符是否可以被改变,以及属性是否可以被删除。如果设置为false,属性将不能被删除,且其属性描述符不能被改变。

        属性描述符的属性树如下:

image.gif 编辑

1.1、属性描述符示例

       属性描述符示例如下:

let descriptor = {
  value: 42,
  writable: true,
  enumerable: true,
  configurable: true
};

image.gif

       在这个例子中,descriptor是一个属性描述符对象,它定义了一个数据属性,该属性具有可写的值、可枚举和可配置的特性。

1.2、用属性描述符定义属性及获取对象的属性描述符

       要使用属性描述符来定义或修改对象属性,可以使用Object.defineProperty()方法,此外,还可以使用Object.getOwnPropertyDescriptor()来获取对象属性的当前属性描述符

let obj = {};
Object.defineProperty(obj, 'myProp', {
  value: 42,
  writable: true,
  enumerable: true,
  configurable: true
});
// 获取对象属性的当前属性描述符
let propDesc = Object.getOwnPropertyDescriptor(obj, 'myProp');
console.log(propDesc);
// 输出:{ value: 42, writable: true, enumerable: true, configurable: true }

image.gif

1.3、带有读取器和设置器的属性描述符

       带有读取器(getter)和设置器(setter)的属性描述符允许你定义属性的获取和设置行为,而不是直接存储一个值。这种属性被称为访问器属性。以下是一个带有读取器和设置器的属性描述符的例子:

let obj = {};
// 定义属性描述符,包含读取器和设置器
let descriptor = {
  get: function() {
    // 这个函数会在访问属性时被调用
    console.log('Getting the value!');
    return this._myValue; // 访问器返回内部属性的值
  },
  set: function(newValue) {
    // 这个函数会在设置属性值时被调用
    console.log('Setting the value to ' + newValue);
    this._myValue = newValue; // 设置器将值存储到内部属性
  },
  enumerable: true, // 属性是否可枚举
  configurable: true  // 属性的描述符是否可以被改变
};
// 使用属性描述符定义属性
Object.defineProperty(obj, 'myProperty', descriptor);
// 测试读取器
console.log(obj.myProperty); // 输出: 'Getting the value!' 然后是 undefined
// 测试设置器
obj.myProperty = 10; // 输出: 'Setting the value to 10'
console.log(obj.myProperty); // 输出: 'Getting the value!' 然后是 10

image.gif

       其中,对obj中myProperty属性进行赋值,就会触发设置器,读取obj的myProperty属性,就会触发读取器。

二、使用属性描述符的情景

2.1、封装和数据隐藏

       使用getter和setter来封装一个对象的内部状态,防止直接访问和修改。
// 使用getter和setter来封装一个对象的内部状态,防止直接访问和修改。
let user = {
  _name: 'Alice',
  get name() {
    return this._name;
  },
  set name(value) {
    if (typeof value === 'string') {
      this._name = value;
    } else {
      console.log('Name must be a string.');
    }
  }
};
console.log(user.name); // Alice
user.name = 'Bob'; // 更新名称
console.log(user.name); // Bob
user.name = 123; // 尝试设置非法名称,将显示错误信息

image.gif

2.2、 创建只读属性

       通过设置writable为false,可以创建一个不允许修改的属性。
// 通过设置writable为false,可以创建一个不允许修改的属性。
let product = {
  _price: 19.99,
  get price() {
    return this._price;
  }
};
Object.defineProperty(product, 'price', {
  writable: false,
  enumerable: true,
  configurable: true
});
console.log(product.price); // 19.99
// product.price = 24.99; // 这将不会改变价格,因为属性是只读的

image.gif

2.3、验证属性赋值

       在setter中添加逻辑来验证属性值,确保它们满足特定条件。
// 在setter中添加逻辑来验证属性值,确保它们满足特定条件。
let account = {
  _balance: 0,
  get balance() {
    return this._balance;
  },
  set balance(amount) {
    if (amount < 0) {
      console.log('Cannot set a negative balance.');
    } else {
      this._balance = amount;
    }
  }
};
account.balance = 1000; // 设置余额
console.log(account.balance); // 1000
account.balance = -500; // 尝试设置负余额,将显示错误信息

image.gif

三、情景:如果属性描述符中writable为false,但是写了set函数

       如果属性描述符中的 writable 属性设置为 false,这意味着属性的值不能被重新赋值。此时如果尝试通过 set 函数修改属性值,它将不会对属性的实际值产生任何影响,因为 writable 属性已经明确禁止了对值的修改。

let obj = {};
let descriptor = {
  value: 42,
  writable: false, // 禁止修改属性值
  set: function(newValue) {
    console.log(`Attempt to set value to: ${newValue}`);
    // 尽管这里尝试设置新值,但由于 writable: false,这个操作不会有任何效果
    // 甚至连`Attempt to set value to: ${newValue}`都不会打印
    // writable: false情况下,不会触发设置器函数
  },
  enumerable: true,
  configurable: true
};
Object.defineProperty(obj, 'myProperty', descriptor);
console.log(obj.myProperty); // 输出: 42
obj.myProperty = 100; // 尝试修改属性值,但会失败
// "Attempt to set value to: 100" 这一行不会被打印
console.log(obj.myProperty); // 输出仍然是: 42
obj.myProperty = 'new value'; // 再次尝试修改属性值,但仍然会失败
console.log(obj.myProperty); // 输出仍然是: 42

image.gif

四、总结与相关资源

       属性描述符还有很多内容可以挖掘,比如defineProperty与Proxy的区别,比如vue2与vue3实现数据劫持的方式有什么不同,实现效果有哪些差异等,这篇博文只是入门,以后有时间再深挖。

       博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

       更多优质内容,请关注:

JS底层逻辑:

       最细最有条理解析:事件循环(消息循环)是什么?进程与线程的定义、关系与差异

       路由通配符,小小的字符有大大的作用,你真的熟悉吗?

       管理数据必备!侦听器watch用法详解

       什么是深拷贝?深拷贝和浅拷贝有什么区别

JS语法篇:

       你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解

       对象数据的读取,看这一篇就够了!

       通过array.every()实现数据验证、权限检查和一致性检查,array.some与array.every的区别

       通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理

       通过array.map()实现数据转换、创建派生数组、异步数据流处理、搜索和过滤等需求

       通过array.reduce()实现数据汇总、条件筛选和映射、对象属性的扁平化、转换数据格式等

       通过array.filter()实现数组的数据筛选、数据清洗和链式调用

巧妙算法与窍门:

       多维数组操作,不要再用遍历循环foreach了,来试试数组展平的小妙招!

       别再用双层遍历循环来做新旧数组对比,寻找新增元素了!

       shpfile转GeoJSON且控制转化精度;如何获取GeoJSON?GeoJson结构详解

       Mapbox添加行政区矢量图层、分级设色图层、自定义鼠标悬浮框、添加天地图底图等

Element plus拓展:

       通过el-tree自定义渲染网页版工作目录,实现鼠标悬浮显示完整名称等

       el-table实现动态数据的实时排序,一篇文章讲清楚elementui的表格排序功能

       el-table中如何添加渐变色带、多色色带

目录
打赏
0
0
0
0
7
分享
相关文章
极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图
本文介绍了使用 Vue Flow 绘制流程图的方法与技巧。Vue Flow 是一个灵活强大的工具,适合自定义复杂的流程图。文章从环境要求(Node.js v20+ 和 Vue 3.3+)、基础入门案例、自定义功能(节点与连线的定制、事件处理)到实际案例全面解析其用法。重点强调了 Vue Flow 的高度灵活性,虽然预定义内容较少,但提供了丰富的 API 支持深度定制。同时,文中还分享了关于句柄(handles)的使用方法,以及如何解决官网复杂案例无法运行的问题。最后通过对比 mermaid,总结 Vue Flow 更适合需要高度自定义和复杂需求的场景,并附带多个相关技术博客链接供进一步学习。
管理数据必备;侦听器watch用法详解,vue2与vue3中watch的变化与差异
一篇文章同时搞定Vue2和Vue3的侦听器,是不是很棒?不要忘了Vue3中多了一个可选项watchEffect噢。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
Vue2+VueRouter2+webpack 构建项目
1). 安装Node环境和npm包管理工具 检测版本 node -v npm -v 图1.png 2). 安装vue-cli(vue脚手架) npm install -g vue-cli --registry=https://registry.
1090 0
|
3月前
|
vue使用iconfont图标
vue使用iconfont图标
177 1
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。
ry-vue-flowable-xg:震撼来袭!这款基于 Vue 和 Flowable 的企业级工程项目管理项目,你绝不能错过
基于 Vue 和 Flowable 的企业级工程项目管理平台,免费开源且高度定制化。它覆盖投标管理、进度控制、财务核算等全流程需求,提供流程设计、部署、监控和任务管理等功能,适用于企业办公、生产制造、金融服务等多个场景,助力企业提升效率与竞争力。
117 12
Vue中的class和style绑定
在 Vue 中,class 和 style 绑定是基于数据驱动视图的强大功能。通过 class 绑定,可以动态更新元素的 class 属性,支持对象和数组语法,适用于普通元素和组件。style 绑定则允许以对象或数组形式动态设置内联样式,Vue 会根据数据变化自动更新 DOM。
Vue Router 简介
Vue Router 是 Vue.js 官方的路由管理库,用于构建单页面应用(SPA)。它将不同页面映射到对应组件,支持嵌套路由、路由参数和导航守卫等功能,简化复杂前端应用的开发。主要特性包括路由映射、嵌套路由、路由参数、导航守卫和路由懒加载,提升性能和开发效率。安装命令:`npm install vue-router`。
iframe嵌入页面实现免登录思路(以vue为例)
通过上述步骤,可以在Vue.js项目中通过 `iframe`实现不同应用间的免登录功能。利用Token传递和消息传递机制,可以确保安全、高效地在主应用和子应用间共享登录状态。这种方法在实际项目中具有广泛的应用前景,能够显著提升用户体验。
299 8