Object.getOwnPropertyDescriptor(obj,'a'):
先来执行一个代码:
let obj = {
a:"1212"
}
console.log("来自ES6的属性描述符对象",Object.getOwnPropertyDescriptor(obj,'a'));
这个方法返回一个属性描述符对象,该对象可能包含以下属性:
value:属性的值。该属性的值可以是任何 JavaScript 类型的值。对于通过Object.defineProperty或Object.create创建的数据属性(即直接赋值而非通过 getter/setter 定义的属性),这个属性会被返回。writable:一个布尔值,表示属性的值是否可以被改变(即是否可以被重新赋值)。get:一个给属性提供 getter 的方法,或者undefined(如果属性没有 getter)。当读取属性时,这个方法会被调用(不带参数),并返回属性的值。set:一个给属性提供 setter 的方法,或者undefined(如果属性没有 setter)。当属性值被修改时,这个方法会被调用,并传入新值作为参数。enumerable:一个布尔值,表示属性是否能在for...in循环和Object.keys方法中被枚举。configurable:一个布尔值,表示属性的描述符是否可以被改变,或者属性是否可以从对象上删除。如果指定的属性在对象上不存在,
Object.getOwnPropertyDescriptor会返回undefined。
👇🏻 那么这个方法返回的属性描述符对象 就是Object.defineProperty可以显示设置的属性描述符对象属性列表!
Object.defineProperty 数据劫持 :
在 JavaScript 中,使用 Object.defineProperty 方法定义或修改对象的属性时,可以传入一个属性描述符(descriptor)对象来指定该属性的各种特性。
Object.defineProperty() 提供了比简单的赋值操作更强大的功能,允许更细致地控制对象属性的行为。
如果属性是通过普通的赋值操作(如 obj.prop = value)创建的,那么该属性默认是可写的(writable: true),并且可以通过后续的操作重新赋值。而 Object.defineProperty 提供了更细粒度的控制,允许你显式地设置这些属性特性。
一句话:Object.defineProperty 提供了比普通赋值更强大的功能,可以显示设置是否可写等属性
注意:
Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, ...
确保你在定义对象属性时
要么只使用value和writable来定义一个非访问器(非getter/setter)属性,
要么只使用get和set来定义一个访问器属性。
如果你需要同时定义访问器属性和非访问器属性,你需要分开定义它们。
let obj = {a:"xxx"};
let year = 1992;
Object.defineProperty(obj,'a',{
get(){
return year;
},
set(newValue){
console.log("数据发生了劫持", newValue);
if(newValue=='0000'){
year = 2004
}
}
});
obj.a="0000";
console.log(obj.a)
应用:Vue2.x 的数据劫持
建议反复阅读下面4句话:
Vue2 中使用Object.defineProperty 实现数据劫持。
vue遍历递归数据对象所有属性,并使用Object.defineProperty为每个属性设置getter和setter。
当数据读取时候,getter会触发依赖收集;
当数据被修改时候,setter会通知所有依赖于该数据的订阅者watcher,触发相应的update更新逻辑。
缺点:下面三种情况数据修改了但视图没有更新 🖤 😱 !
1、利用索引直接设置一个项时,例如: vm.items[indexOfItem] = newValue
2、修改数组的长度时,例如: vm.items.length = newLength
3、直接给对象赋值新属性,例如: vm.items.newKey = newValue
原因:
受ES5限制,vuejs不能检测到对象属性的添加或删除。
因为vuejs在初始化实例时将属性转为getter/setter。
所以属性必须在data对象上才能让vue转换他,才能是响应的。
这也是问:动态给vue的data添加一个新的属性时为什么页面不更新的答案
解决方案: ❤ 😄 💃🏻
vue 内部通过重写这个函数解决了这个问题:通过使用
Vue.set(target, key, value)。
但是在vue3.0中已经不使用这种方式了,而是通过Peoxy对对象进行代理,从而实现数据劫持。缺点是是ES6的语法,有兼容性问题。
还可以使用
- Object.assign():要生成新的对象
- $forcecUpdated(): 不建议使用