Object.defineProperty 方法

Object.defineProperty是es5中新增加的属性描述符。在它出现之前你可能会经常有一些疑问,比如for in 循环为何不能遍历出函数的arguments、length、name等属性名,delete window.a 为何返回false, 等你学完这个api,这些现象便都能够得到解释。

Object.defineProperty 一共涉及6个可配置项:

    writable:	是否可重写

    value:  	当前值

    get:    	 读取时内部调用的函数

	set:        写入时内部调用的函数
	
	enumerable: 	是否可以遍历

	configurable: 	是否可再次修改配置项

我们先试图定义一个简单的对象如下:

var obj = {x:1}

看上去非常简单的一句代码,但它的定义细节比我们看到的要复杂的多,上边这句代码可以转换为es5的以下定义:

	var obj = Object.create(
		Object.prototype,{
			x: {
			 value:1,
			 writable:true,
			 enumerable: true,
			 configurable: true
			}
		 }
	)

实际上在es3中也有 [[ReadOnly]] 、 [[DontEnum]]、 [[DontDelete]] 这样的数据属性,对应了es5 中的访问器属性 [[writable]] 、 [[Enumerable]] 、[[Configurable]]

下面来看下Object.defineProperty的具体用法:

Object.defineProperty方法有三个参数,第一个参数为要定义或修改的对象-object。第二个参数为对象的属性名-string, 第三个参数为配置项。

var obj ={};

Object.defineProperty(obj,"a",{
    value:12,
    writable:true,
    enumerable:true,
    configurable:true
})

console.log(obj.a); // 12

obj.a = 'abc';

console.log(obj.a); // abc

for(var i in obj)
console.log(i); // a

对象默认是可修改可遍历的,修改对象为不可写,它的属性值便不会被改变,类似于我们用const定义一个常量。 定义为不可遍历,那么它对应的那个属性便无法被遍历,这就可以解释我们开头讲到的为什么无法遍历函数的arguments、length、name等属性名。


var obj ={};

Object.defineProperty(obj,"a",{
    value:100,
    writable:false,
    enumerable:false,
    configurable:true
})

console.log(obj.a);// 100

obj.a = "ccc";    // 不会报错,但没法修改值

console.log(obj.a); // 100

for(var key in obj)  // 不会被执行,因为不可遍历
console.log(key);

configurable默认是false,属性值不可修改或删除

var obj ={};

var obj = Object.defineProperty({},"a",{
    value:"aaa"
})

delete obj.a;  //  不会报错,但此属性不会被删除

console.log(obj.a);  // aaa

obj.a = 'bbb';	

console.log(obj.a); // aaa

重头戏! get和set的读写监听:


var obj ={};

Object.defineProperty(obj,"b",{
    set:function(a){
        console.log("正在进行赋值"+a);
    },
    get:function(){
        return "aaa"
    }
})

obj.b="bbb"; // 正在进行赋值bbb
console.log(obj.b); // aaa


兴许你会觉得上边的这段代码很简单,但是这个get和set的api其实异常强大。时下比较流程的mvvm的框架都是基于Object.defineProperty这个api进行封装的,尤其是set方法的监听使用使得前端产生了数据驱动的思想。但是由于Object.defineProperty这个api在IE8中有bug,所以只能用于IE9+,所以相应的市面流行的React 、vue等框架也只能兼容到IE9+ 。

Object.defineProperty这个api虽然强大,但同样存在着一些问题。除了我们上边提到的浏览器兼容性,它在各浏览器的实现也略有差异。另外当Object.prototype被污染时,使用Object.defineProperty很容易程序崩溃,这种情况在各大浏览器均会出现。因此在计划使用这个api封装自己的框架之前最好还是更加深入的学习了解一下,收集一些专业的hack补丁。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章