浅谈js对象之数据属性访问器属性Object.defineProperty方法
Posted homestrong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈js对象之数据属性访问器属性Object.defineProperty方法相关的知识,希望对你有一定的参考价值。
一、对象
这个不用多说,常见的几种创建对象的方法有:
1.通过构造函数创建对象,如下所示:
function Person(){ } var person = new Person();
2.通过Object创建简单对象,例如:
var obj = new Object();
3.通过字面量创建对象。
var obj = {};
常用的一般是第一种和第三种方法。
二、属性类型
javascript中有两种属性:数据属性和访问器属性,确切的说这两种特性是用来描述对象属性的各种特征,比如说这个对象属性的值能否被改变,因为这些特性是内部值,而javascript又不能直接访问,所以在规范中把他们放在了两对儿化括号中,例如[[Enumerable]]。下面 来看看这两种具体的内部属性。
1.数据属性
数据属性包含一个数据值。在这个位置可以读取和写入值,
[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,能否把属性修改为访问器属性(这个后面会说),默认为true;
[[Enumerable]]:用来修饰对象属性的枚举特性,表示能否通过用for in循环返回属性,默认为true;
[[Writable]]:用来修饰对象属性值的可写特性,默认为true;
[[Value]]:包含这个属性的数据值,访问器属性里面是没有这个特性的。默认为undefined;比如var person = {name:‘lili‘},这里设置了一个名叫name的属性,它的值是"lili", [[Value]]特性将被设置为"lili",其余的是三个特性都是默认值true。
下面就用具体的实例来理解上面的特性。首先这里要先谈的是Object.defineProperty()方法,这个方法接收三个参数:属性所在的对象、属性的名字、和一个描述符对象(也就是上面的四个数据属性,用来描述对象属性的特性),这里要注意了,采用Object.defineProperty方法创建属性时候,数据属性[[configurable]]、[[writable]]、[[enumerable]]默认为false,这要和字面量直接声明属性时默认值相反,但是如果只是用Object.defineProperty改变原来已有属性的值则没有此限制,具体看下面例子:
var person = {};
Object.defineProperty(person,‘name‘,{ //创建name属性 value:‘lili‘, }); console.log(person.name); //lili person.name = ‘shasha‘; //writable默认是false 不可改动属性值 console.log(person.name); //lili
修改writable的值为true可以看到,person.name的值打印出来是‘shasha‘;
var person = {}; Object.defineProperty(person,‘name‘,{//创建name属性 writable:true, value:‘lili‘, }); console.log(person.name); //lili person.name = ‘shasha‘; //writable设置为true, 属性值被重写 console.log(person.name); //shasha
但是当person里面有属性,采用Object.defineProperty方法只是修改特性和值时,默认值都为true,具体请看下面示例:
var person = {age:22}; Object.defineProperty(person,‘age‘,{ //重新定义修改age属性 value:33, }); person.age = 66; console.log(person.age); //66 说明writable此时为true,
设置[[enumrable]]特性的规则跟[[writable]]相同,为true时才能用for in 循环遍历出属性。下面来重点看看[[Configurable]]特性的作用,例子如下:
var person = {}; Object.defineProperty(person,‘name‘,{ configurable:false, value:‘lili‘, }); console.log(person.name); //lili delete person.name; console.log(person.name); //lili
把configurable设置为false,表示不能删除对象属性,对这个这个属性调用delete方法,非严格模式下什么也不会发生,严格模式下则会抛出错误,而且一旦把属性从configurable设置为false,以后就不能把它设置为true,此时在调用Object.defineProperty方法修改除writable、value之外的特性,都会导致错误,看下面例子:
var person = {}; Object.defineProperty(person, ‘name‘, { configurable: false, enumerable: true, writable: true, value: ‘lili‘, }); Object.defineProperty(person, ‘name‘, { // configurable: true, //会报错额! // enumerable: false, //会报错的! writable: false, value: ‘tangtang‘, }); person.name = ‘wangdachui‘; console.log(person.name);//tangtang
2.访问器属性
访问器属性不包括数据值,它包含一对getter和setter函数,在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,访问器属性有如下四个特性:
[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,能否把属性修改为数据属性(这个后面会说),默认为true;
[[Enumerable]]:用来修饰对象属性的枚举特性,表示能否通过用for in循环返回属性,默认为true;
[[Get]]:在读取属性时候调用的函数,默认为undeifne;
[[Set]]:在写入属性时候调用的函数,默认为undeifne;
访问器属性不能直接定义,必须使用Object.defineProperty()来定义。请看下面的例子。
var book = { _year: 2018, edition: 1, }; Object.defineProperty(book, ‘year‘, { get: function () { alert(‘通过对象方法访问 哈哈!‘); return this._year; }, set: function (newValue) { if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; alert(this.edition); } } }); console.log(book.year) //通过对象方法访问 get函数里面alert出对应信息; book.year = 2005; console.log(book.edition); //2
以上例子中,book对象有两个默认属性:_year 和 edition ,其中_year前面加了下划线,用于表示只能通过对象方法去访问这个属性,即通过get方法返回属性值。如果直接访问book.edition的值,则不会调用get方法返回。book.year=2005即是修改book的year属性值,会调用set方法,参数newValue就是设置的2005这个值,在上面例子中set函数里还改变了属性edition的值。
3.定义多个属性
采用Object.defineProperties我们也可以为一个对象定义多个属性,这个方法有两个参数:第一个要定义属性的对象,第二个也是对象,表示要添加的多个属性和其对应的属性描述符,具体怎么添加呢,请看下面的例子:
var book = {}; Object.defineProperties(book,{ _year:{ writable:true, value:2004, }, edition:{ writable:true, value:1, }, year:{ get:function(){ return this._year; }, set:function(newValue){ if(newValue > 2004){ this._year = newValue; this.edition += newValue - 2004; } } } });
以上代码在book对象上定义了两个数据属性(_year和edition)和一个访问器属性(year)。
4.读取属性的特性
上面我们一直是在讨论如何设置属性的描述特性,那么对于数据属性和访问器属性里面的具体特性我们怎么读取呢?这里介绍另一个Object的方法:getOwnPropertyDescriptor方法,该方法接收两个参数:属性所在的对象和要读取其描述符的属性名称,它的返回是一个对象,来我们来看看具体的实例:
var book = {}; Object.defineProperties(book, { _year: { writable: true, value: 2004, }, edition: { writable: true, value: 1, }, year: { get: function () { return this._year; }, set: function (newValue) { if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } } }); book.year = 2005; console.log(book.edition); //2 var descriptor1 = Object.getOwnPropertyDescriptor(book, ‘_year‘); console.log(descriptor1.value); //2005 console.log(descriptor1.configurable);//false console.log(typeof descriptor1.get); //undefine var descriptor2 = Object.getOwnPropertyDescriptor(book, ‘year‘); console.log(descriptor2.value); //2005 console.log(descriptor2.configurable);//false console.log(typeof descriptor2.get); //function;
以上是关于浅谈js对象之数据属性访问器属性Object.defineProperty方法的主要内容,如果未能解决你的问题,请参考以下文章