Javascript 什么时候使用Object.defineProperty()
我在想我什么时候该用Javascript 什么时候使用Object.defineProperty(),javascript,ecmascript-5,Javascript,Ecmascript 5,我在想我什么时候该用 Object.defineProperty 为对象创建新特性的步骤。我知道我可以设置如下内容 enumerable: false 但你什么时候真的需要这个?如果您只设置一个属性,如 myObject.myprop = 5; 它的描述符都设置为true,对吗?实际上,我更好奇的是,当你们使用对.defineProperty()的那个相当冗长的调用时,是出于什么原因。主要用于设置具有特定属性描述符的属性(例如只读(常量)、可枚举性(不在循环中显示属性、getter、set
Object.defineProperty
为对象创建新特性的步骤。我知道我可以设置如下内容
enumerable: false
但你什么时候真的需要这个?如果您只设置一个属性,如
myObject.myprop = 5;
它的描述符都设置为true,对吗?实际上,我更好奇的是,当你们使用对.defineProperty()的那个相当冗长的调用时,是出于什么原因。主要用于设置具有特定属性描述符的属性(例如只读(常量)、可枚举性(不在循环中显示属性、getter、setter)
例子
此方法使用属性扩展对象
原型。仅定义getter,可枚举性设置为false
Object.defineProperty(Object.prototype, '__CLASS__', {
get: function() {
return Object.prototype.toString.call(this);
},
enumerable: false // = Default
});
Object.keys({}); // []
console.log([].__CLASS__); // "[object Array]"
像“可枚举”这样的功能在我的经验中很少使用。 主要用例是计算属性:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
Object.defineProperty(myObj, 'area', {
get: function() {
return this.width*this.height;
}
});
console.log(myObj.area);
使用Object.defineProperty的一个很好的理由是,它允许您将对象中的函数作为计算属性进行循环,该属性执行函数而不是返回函数体 例如:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
Object.defineProperty(myObj, 'area', {
get: function() {
return this.width*this.height;
},
enumerable: true
});
for (var key in myObj) {
if (myObj.hasOwnProperty(key)) {
console.log(key + " -> " + myObj[key]);
}
}
//width -> 20, height -> 20, area -> 400
let logErrorTimeoutId = setTimeout(() => {
if (error) {
console.error('Unhandled (in <your library>)', error.stack || error);
}
}, 10);
Object.defineProperty(data, 'error', {
configurable: true,
enumerable: true,
get: () => {
clearTimeout(logErrorTimeoutId);
return error;
},
});
与将函数作为属性添加到对象文字相比:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
myObj.area = function() {
return this.width*this.height;
};
for (var key in myObj) {
if (myObj.hasOwnProperty(key)) {
console.log(key + " -> " + myObj[key]);
}
}
// width -> 20, height -> 20, area -> function() { return this.width*this.height;}
确保将enumerable属性设置为true,以便循环使用它。@Gerard Simpson
如果“区域”应该是可枚举的,那么它也可以在没有Object.defineProperty的情况下写入
var myObj = {
get area() { return this.width * this.height }
};
myObj.width = 20;
myObj.height = 20;
for (var key in myObj) {
if (myObj.hasOwnProperty(key)) {
console.log(key + " -> " + myObj[key]);
}
}
//area -> 400, width -> 20, height -> 20
我所看到的
defineProperty
的一个简洁的用例是,库向用户提供一个错误属性,如果在某个时间间隔内没有访问它,您就会抛出自己的错误属性。例如:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
Object.defineProperty(myObj, 'area', {
get: function() {
return this.width*this.height;
},
enumerable: true
});
for (var key in myObj) {
if (myObj.hasOwnProperty(key)) {
console.log(key + " -> " + myObj[key]);
}
}
//width -> 20, height -> 20, area -> 400
let logErrorTimeoutId = setTimeout(() => {
if (error) {
console.error('Unhandled (in <your library>)', error.stack || error);
}
}, 10);
Object.defineProperty(data, 'error', {
configurable: true,
enumerable: true,
get: () => {
clearTimeout(logErrorTimeoutId);
return error;
},
});
让logErrorTimeoutId=setTimeout(()=>{
如果(错误){
console.error('Unhandled(in'),error.stack | | error);
}
}, 10);
Object.defineProperty(数据“错误”{
对,,
可枚举:正确,
获取:()=>{
clearTimeout(logErrorTimeoutId);
返回误差;
},
});
此代码的源代码:当您需要执行一些拦截或以优雅的方式应用经典的观察者/可观察模式时,一个很好的用途是: 总结: 在Javascript中,对象是键值对的集合。
Object.defineProperty()
是一个函数,它可以在对象上定义新属性,并可以设置属性的以下属性:
- 值
:与键关联的值 - writable
:如果writable设置为
,则可以通过为其分配新值来更新该属性。如果设置为true
,则无法更改该值false
- enumerable
:如果enumerable设置为true,则可以通过
for..在
循环中访问
属性。此外,与
Object.keys()一起返回的可枚举属性键是唯一的
- 可配置
:如果可配置设置为
,则无法更改属性属性属性(值/可写/可枚举/可配置),同时,由于无法更改值,因此无法使用false
删除
操作符将其删除
让obj={};
Object.defineProperty(对象“prop1”{
价值:1,
可写:false,
可枚举:false,
可配置:false
});//创建一个新属性(key=prop1,value=1)
Object.defineProperty(obj,“prop2”{
价值:2,
可写:对,
可枚举:正确,
可配置:true
});//创建一个新属性(key=prop2,value=2)
console.log(obj.prop1,obj.prop2);//两个prop都存在
用于(obj中的常量道具){
控制台日志(道具);
//只记录prop2,因为可写在prop2中为true,在prop1中为false
}
obj.prop1=100;
obj.prop2=100;
控制台日志(obj.prop1,obj.prop2);
//只更改了prop2,因为prop2可写,而prop1不可写
删除obj.prop1;
删除obj.prop2;
控制台日志(obj.prop1,obj.prop2);
//仅删除prop2,因为prop2是可配置的,而prop1不是对象。defineProperty可防止您意外地将值分配给其原型链中的某个键。。使用此方法,您只能将值分配给该特定对象级别(而不是原型链中的任何键)
例如:
有一个像{key1:value1,key2:value2}
这样的对象,您不知道它的原型链,或者错误地错过了它,并且原型链中的某个地方有一些属性“color”-
使用点(.)赋值-
此操作将为原型链中的键“颜色”赋值(如果某个地方存在键),您将发现对象没有变化。
obj.color='blue';//obj保持与{key1:value1,key2:value2}相同
使用Object.defineProperty方法-
Object.defineProperty(obj, 'color', {
value: 'blue'
});
//现在obj看起来像{key1:value1,key2:value2,color:'blue'}
。它将属性添加到相同的级别。然后您可以使用方法对象.hasOwnProperty()
安全地迭代,例如:
当您将普通JavaScript对象作为其数据
选项传递给Vue实例时,Vue将遍历其所有属性,并使用对象将其转换为getter/setters
。defineProperty
。这是一个仅限ES5且不可填充的功能,这就是Vue不支持IE8及以下版本的原因
getter/setter对用户是不可见的,但在后台,它们使Vue能够在访问或修改属性时执行依赖项跟踪和更改通知
[……]
请记住,即使是Vue.js的超薄基本版本也会使用一些东西,而不仅仅是Object.defineProperty
,但主要功能来自它:
在这里,您可以看到一篇文章,作者实现了Vue.js之类的最低PoC版本:
这里是一个演讲(西班牙语),演讲者在解释Vue.js中的反应时构建了类似的内容:非常有用