属性类型

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)方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。
参数:

obj:要在其上定义属性的对象。
prop:要定义或修改的属性的名称。
descriptor:将被定义或修改的属性描述符。

返回值:

被传递给函数的对象。

属性描述符:

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数组会获取日志条目。

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指向某个被访问和修改属性的对象。

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

不像访问者属性,值属性始终在对象自身上设置,而不是一个原型。然而,如果一个不可写的属性被继承,它仍然可以防止修改对象的属性。

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

Lessong
101 声望4 粉丝

下一篇 »
vue混入。