JavaScript中数据属性和访问器属性

    JavaScript中创建自定义对象有两种方法。

    一种是对象字面量法,例如:

var person ={
     name:"xiaochang",
     age:24,
     sayName:function(){
          alert(this.name);   
     }
}

    另一种是用new运算符创建一个Object()的实例,然后再为其添加属性和方法。例如:

var person = new Object();
person.name = "xiaochang";
person.age = 24;
person.sayName = function(){
     alert(person.name);
}

属性类型及其特性

    JavaScript中定义了两种不同的属性:数据属性和访问器属性。数据属性一般用于存储数据值,而访问器属性一般进行get/set操作,不能直接存储数据值。在ES5中,为了描述属性(property)的各种特征,定义了4个描述其行为的特性(attribute)。在JavaScript中不能直接访问特性,要放在两对方括号中。

数据属性:

数据属性主要有四个特性描述其行为:

1、[[Configurable]]:默认为true。表示能够通过delete删除属性,能否修改属性特性,或把属性修改为访问器属性;

2、[[Enumerable]]:默认为true。表示能否通过for-in循环返回属性;

3、[[Writable]]:默认为true。表示能否修改属性的值;

4、[[value]]:默认为undefined。包含这个属性的数据值。读取和写入属性值时都从这个位置进行。

 

 直接在对象上定义的属性,其数据特性默认如下:

1、[[Configurable]]:true

2、[[Enumerable]]:true

3、[[Writable]]:true

4、[[Value]]:“xiaochang"(初始时的赋值)

    这些特性不能直接被访问,要修改属性的特性只能通过Object.defineProperty()方法。该方法包含三个参数:

属性所在的对象,属性的名字,一个描述符对象(包含上述四个特性的一个或多个)。 

var person = {
      age:100 ;
}

Object.defineProperty(person,"name",function{
      configurable:false;
      writable:false;
      value:"xiaochang";
});

Object.defineProperty(person,"tall",{
      value:160;
});

for (attr in perso){
            console.log(attr);   //name,age
}

console.log(person.name);//xiaochang
person.name="CC";         //为name属性指定新值
console.log(person.name);//xiaochang
delete person.name;        //删除name属性
console.log(person.name);//xiaochang

console.log(person.age);   //100
person.age=200;             //为age属性指定新值
console.log(person.age);   //200
delete person.age;           //删除age属性
console.log(person.age);  //undefined

console.log(person.tall);  //160
person.tall=170;            //修改tall属性的值
console.log(person.age); //160
delete person.tall;          //删除tall属性
console.log(person.tall); //160

 

    直接在对象上定义的属性,如age,[[Configurable]]、[[Enumerable]]、[[Writable]]特性都被设置为true。

    属性name的[[Configurable]]、[[Writable]]被设置为false。所以无法修改和删除。

    调用Object.defineProperty()方法时,如果不显示指定configurable、enumerable、writable的值,就默认为false。如属性tall。

    需注意的是,当configurable设置为false后无法再将其改为true。且除了writable之外,无法修改其他特性。在configurable为true的情况下,可多次调用Object.definePro[erty()修改同一属性。

访问器属性:

    包含getter和setter函数。读取访问器属性时,调用getter函数,返回有效的值;在写入访问器属性时,调用setter函数传入新值。它包含了4个特性:

1、[[Configurable]]:表示是否能通过delete删除属性从而重新定义属性,能否修改属性的特性,能否把属性修改为数据属性;

2、[[Enumerable]]:表示能否用for-in循环返回。

3、[[Get]]:读取属性时调用的函数,默认为undefined;

4、[[Set]]:写入属性时调用的函数,默认为undefinef。

    getter和setter不一定要成对出现,只有getter函数表明该属性只可读不可写,只有setter函数表明该属性只可写不可读。

访问器属性无法直接定义,必须使用Object.defineProperty()来定义。

var person = {
      _name:"xiaochang",    //name属性只可读不可写
      _age:100,                   //age属性只可写不可读
      _tel:123456               //tel属性可读可写
};
Object.defineProperty(person,"name",{
      get:function(){
            return this._name;
}
});
Object.defineProperty(person,"age",{
      set:function(newage){
            this._age=newage;
}  
}) ;
Object.defineProperty(person,"tel",{
       get:function(){
             return this._tel;
       },
       set:function(newtel){
       this._tel=newtel;
       }
});

console.log(person.name);   //"xiaochang"
person.name="CC";            //尝试修改name属性
console.log(person.name);   //"xiaochang"
console.log(person.age);      //undefined,不可读属性
person.age=200;                //修改age
console.log(person._age);   //直接读取对象方法才能访问的属性。可以看到值已更新为200
console.log(person.tel);     //123456
person.age=654321;         //修改tel
person.log(person.tel);       //654321

 

    属性前的下划线,表示只能通过对象方法访问的属性,当调用Person.name时实际调用了name属性的getter函数(直接调用person._name可得到相同的结果,这样做访问器就没有什么意义了)。为person.name赋值时调用的是name属性的setter函数。

定义多个属性:

    ECMAScript 5还提供了一个对对象定义多个属性的方法,Object.defineProperties()。该方法接受两个参数:属性所在的对象,多个属性的名字和其描述符对象组成的对象。上面的例子可以改写成如下:

var person = {
      _name:"xiaochang",
      _age:100,
      _tel:123456
};
Object.defineProperties(person,{
     name:{
                 get:function(){
                       return this._name;
                 }
     },
     age:{
              set:function(newage){
                    this._age = newage;
              }    
     },
     tel:{
            get:function(){
                  return this._tel;
            },
            set:function(newtel){
                  this._tel = newtel;
            }
     }
});

 

 

读取属性的特性:

  对于上述属性特性,ECMAScript 5给出了可以取得给定属性的描述符的方法

    Object.getOwnPropertyDescriptor(),该方法包含两个参数:属性所在的对象,要读取器描述符的属性名称。方法返回一个对象,如果是访问器属性,返回的对象有configuable、enumerable、get和set;如果是数据属性,这个返回对象的属性包括configuable、enumerable、writable和value。如:

var descriptor = Object.getOwnPropertyDescriptor(person,"tel");
for (attr in descriptor){
     console.log(attr+":"+descriptor[attr]);
}
//运行结果如下:
get:function(){return this._tel;}
set:function(newtel){this._tel=newtel;}
enumerable:false
configurable:false

 

数据属性和访问器属性的作用:

先看代码

var obj ={name:"percy"};
console.log(obj.name);         //percy
boj.name = "zyj";
console.log(obj.name);        //zyj

//这里借Math对象来举例
//首先说明一下,Math对象和上面定义的ogj对象都只是Object对象的一个实例
console.log(Math.PI);         //3.1415926…
Math.PI=1234;
console.log(Math.PI);        //3.1415926…

 

同样是Object的实例,obj对象的属性却可以被改写,而Math对象的属性却不能被改写。

这是因为,通过new运算符或对象字面量直接在对象上定义的属性,它们的[[Configurable]]、[[Enumerable]]、[[Writable]]特性默认都被设置为true。[[Value]]则被设定为指定的值。

如果要让Obj对象的属性也不能被改写,就要用到Object.defineProperty()方法。

若不按照上面2种方法为对象添加属性,而直接通过Object.defineProperty()为对象添加属性以及值,这种情况下,该对象的这个属性的另外3个特性的默认值都是false。

var person={};    //新建一个空对象
Object.defineProperty(person,"name",{
          value:"perch"
});
console.log(Object.getOwnPropertyDescriptor(person,"name"));
//打印:Object{value:"percy",configurable:false,enumerable:false,writable:false}

 

访问器属性则是用来实现JavaScript引擎本身使用得,因此不建议开发者使用访问器属性。

 

posted @ 2017-04-24 23:40  海盗洁哥  阅读(332)  评论(0编辑  收藏  举报