ECMAScript中有两种属性:数据属性和访问器属性。
数据属性:
数据属性包含一个数据值的位置。在这个位置能够读取和写入值。数据属性有4个描述其行为的特性。数组
[[Configurable]]:表示可否经过delete删除属性从而从新定义属性,可否修改属性的特性,或者可否把属性修改成访问器属性。在对象上直接定义的属性,它们的这个特性默认值为true。 [[Enumerable]]:表示可否经过for-in循环返回属性。在对象上直接定义的属性,它们的这个特性默认值为true。 [[Writable]]:表示可否修改属性的值。在对象上直接定义的属性,它们的这个特性默认为true. [[Value]]:包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为undefined。
要修改属性默认的特性,必须使用ECMAScript5的Object.defineProperty()方法。这个方法接受三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符对象的属性必须是:configurable、enumerable、writable和value。设置其中的一个或多个值,能够修改对应的特性值。例如:函数
var person = {}; Obejct.defineproperty(person,'name',{ writable:false, value:'Nics' }) console.log(person.name)//Nics person.name = 'tom'; console.log(person.name)//Nics
这个例子建立了一个明为name的属性,它的值是只读的,若是为它指定新的值,在非严格模式下,赋值操做将被忽略;在严格模式下赋值操做将会抛出错误。
若是把configurable设置为false,表示不能从对象中删除属性,并且一旦把属性定义为不可配置的,就不能再把它变为可配置了。此时再调用Object.defineProperty()方法修改writable以外的特性都会抛出错误。
也就是说,能够屡次调用Object.defineProperty()方法修改同一个属性,但在把configurable特性设置为false以后就会有限制了。
再调用Object.defineProperty()方法建立一个新的属性的时候,若是不指定configurable、enumerable、writable特性的默认值都是false。
Obejct.defineProperty(obj,prop,descriptor)方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。
参数:this
obj:要在其上定义属性的对象。 prop:要定义或修改的属性的名称。 descriptor:将被定义或修改的属性描述符。
返回值:prototype
被传递给函数的对象。
属性描述符:日志
configurable:当且仅当改属性的configurable为true时,该属性描述符才可以被改变,同时该属性也能从对应的对象上被删除。默认为false。 enumerable:当且仅当改属性的enumerable为true时,改属性才可以出如今对象的枚举属性中。默认为false。 数据描述符同时具备如下可选键值: value:该属性对应的值。能够是任何有效的JavaScript值(数值,对象,函数等)。默认为undefined。 writable:当且仅当该属性的writable为true时,value才能被赋值运算符改变。默认为false。 存取描述符同时具备如下可选键值: get:一个给属性提供getter的方法,若是没有getter则为undefined。当访问改属性时,该方法会被执行,方法执行时没有参数传入,可是会传入this对象(因为继承关系,这里的this并不必定是定义该属性的对象)默认为undefined。 set:一个给属性提供setter的方法,若是没有setter则为undefined。当属性值修改时,触发执行该方法。该方法将接受惟一参数,即改属性新的参数值。
var o = {} //在对象中添加一个属性与数据描述符的示例。 Obejct.defineProperty(o,'a',{ value:37, writable:true, enumerable:true, configurable:true }) //对象o拥有了属性a,值为37 //在对象中添加一个属性与存取描述符的示例。 var bValue; Obejct.defineProperyty(o,'b',{ get:function(){ return bValue; }, set:function(newValue){ bValue = newValue; }, enumerable:true, configurable:true }) o.b = 38; //对象o拥有了属性b,值为38. //数据描述符和存取描述符不能混合使用。
通常的Setters和Getters
下面的例子展现了如何实现一个自存档对象。当设置temperature属性时,archive数组会获取日志条目。code
function Archiver(){ var temperatrue = null; var aechive = []; Obejct.defineProperty(this,'temperatrue',{ get:function(){ console.log('get!'); return temperature; }, set:function(value){ temperature = value; archive.push({val:temperature}) } }); this.getArchive = function(){return archive} } var arc = new Archiver(); arc.temperature;//'get!'; arc.temperature = 11; arc.temperature = 13; arc.getArchive();//[{val:11},{val:13}]
或:对象
var pattern = { get:function(){ return 'I alway return this string,whatever you have assigned' }, set:function(){ this.myname = 'this is my name string' } } function TestDefineSetAndGet(){ Object.defineProperty(this,'myproperty',pattern); } var instance = new TestDefineSetAndGet(); instance.myproperty = 'test'; console.log(instance.myproperty); console.log(instance.myname)
若是访问者的属性是被继承的,他的get和set方法会在子对象的属性被访问或者修改时被调用。若是这些方法用一个变量存值,该值会被全部对象共享。继承
function myclass(){} var value; Obejct.defineProperty(myclass.prototype,'x',{ get(){ return value; }, set(x){ value = x; } }) var a = new myclass(); var b = new myclass(); a.x=1; console.log(b.x);//1
在get和set方法中,this指向某个被访问和修改属性的对象。ip
function myclass(){} Obejct.defineProperty(myclass.prototype,'x',{ get(){ return this.stored_x; }, set(x){ this.stored_x = x; } }); var a = new myclass(); var b = new myclass(); a.x=1; console.log(b.x)//undefined
不像访问者属性,值属性始终在对象自身上设置,而不是一个原型。然而,若是一个不可写的属性被继承,它仍然能够防止修改对象的属性。get
function myclass() { } myclass.prototype.x = 1; Object.defineProperty(myclass.prototype, "y", { writable: false, value: 1 }); var a = new myclass(); a.x = 2; console.log(a.x); // 2 console.log(myclass.prototype.x); // 1 a.y = 2; // Ignored, throws in strict mode console.log(a.y); // 1 console.log(myclass.prototype.y); // 1