深入探究JavaScript对象系列(二)

       上文中提到JavaScript对象是属性的集合,本结就来谈谈对象的属性以及对属性的操作。个人认为,JavaScript中对象的属性比其他语言复杂很多,由于本屌的主业是PHP,因此当初看书时候也花了很多时间才把这部分内容给理清了。

 

 

一.JavaScript属性概述

       跟传统的面向对象不太一样,JavaScript对象是动态的,即可以随时对一个js对象新增或删除属性,对属性最常见的操作是设置、查找、删除、检测、枚举。除此以外,每个属性还有一些与之相关的值,称为“属性特性”:

  • 可写:表明该属性是否可以设置该属性的值;
  • 可枚举:表明是否可以通过for/in循环返回该属性;
  • 可配置:表明是否可以删除或创建该属性。

       正是由于上述3中属性特性使得JavaScript中属性相对其他语言来说复杂了很多。此外,根据属性的定义位置,可以把属性分为:

  • 自有属性:直接在对象中定义的属性;
  • 继承属性:在对象的原型对象中定义的属性。

 

 

二.对属性的设置和查询

      由于对象的属性一部分是由自己定义,还有一部分属性是从原型对象那继承下来,因此假如要查询对象o中的属性x时,如果o中不存在,js引擎将会陆续在o的原型对象中来寻找x,如果整条原型链中都找不到或者找到一个原型是null的对象,则返回undefined

var o = {};
o.x = 1;
p = inherit(o);  //创建一个新对象p,原型对象为o,inherit函数请查看上一篇
console.log(p.x);  //返回1,由于在对象p中找不到属性x,则js引擎在它的原型对象中继续查找

       现在假设给给对象o的属性x赋值,如果o中以及有自有属性x,则赋值操作值就直接改变该属性的值,如果不存在,则赋值操作给o新增这个属性x。如果o中的原型链中也有该属性,则继承的属性就被这个新创建的属性覆盖了。

       上述对属性的赋值是基于一种理想情况,事情往往不会那么简单,上面以及提到,每一个属性都有3个属性特性:可写、可枚举、可设置,如果对象o中继承了一个只读属性的x,则赋值操作是不被允许的。

        在JavaScript中,只有在查询属性时,才能体会到继承的存在。

 

 

三.删除对象的属性

       删除一个JavaScript对象的属性可以使用delete运算符,然而需要注意的是:delete只是断开属性和宿主对象的联系,而不会去操作属性中的属性,在销毁一个对象时应特别注意这点;此外delete只能删除自有属性,不能删除继承属性,因此如果要删除继承属性,需要先找到原型链中的该拥有该属性的对象才能删除它。

       如果碰到那种可配置性为false的属性,如通过变量声明或函数声明创建的全局的对象,是不能被删除的,在严格模式下,删除一个不可配置的属性会报一个类型错误。

 

 

四.属性的检测和枚举

       检测一个属性是否属于某个对象有以下几种方法:

  • in运算符:如果对象的自有属性或继承属性中有这个属性则返回true;
  • hasOwnProperty():对象的这个方法用来检测给定的名字是不是对象的自有属性,对于继承的属性返回false;
  • propertyIsEnumerable():该方法是hasOwnProperty()方法的增强版,只有检测到是自有属性且该属性是可枚举的才返回true;
    var o ={};
    o.x = 1;
    p = inherit(o);
    p.y = 2;
    
    o.hasOwnProperty("x");   //返回true
    p.hasOwnProperty("x");   //返回false
    
    Object.property.propertyIsEnumerable("toString");   //返回false,toString()方法不可枚举
    

     

       通过for/in循环可以遍历出对象中所有可枚举的属性(包括自有属性和继承属性),一般来说,对象的内置方法是不可枚举的,但在代码中定义的属性通常都是可以枚举,除非显式地指定该属性为不可枚举,例如:

var o ={x:1 , y:2, z:3};

o.propertyIsEnumerable("toString");  //返回false

for(p in o){
  console.log(p);
}          //循环输出1,2,3,但不会输出toString.

       在ECMAScript5中定义了两个用于枚举属性名称的函数Object.keys()和Object.getOwnPropertyNames(),前者返回一个由对象中可枚举且自有属性组成的数组,后者也返回一个数组,但是它返回的是自有属性的名称,不管其是否可枚举,在ECMAScript3中可以用以下方法来模拟前者:

1 function keys(o){
2     if(typeof o !== "object") throw TypeError();
3     var result = [];
4     for(prop in o){
5         if (!o.hasOwnProperty(prop)) continue;
6         else result.push(prop);
7     }
8     return result;
9 }

 

 

五.属性getter和setter

       在ECMAScript5中,属性值可以用一个或两个方法替代,这两个方法就是getter和setter,由这两个方法定义的属性称作“存取器属性”,不同于“数据”属性,它不具有写属性。

       如果一个存取器属性同时具有getter和setter方法,则这个属性是可读写的,如果只有getter那么它就是个只读属性;如果只有setter方法,则是一个只写属性,读取它时返回undefined

var o ={
    x : 2,
    y : 3,

    get z(){
        return this.x*this.y;
    },
    set z(value){
        this.x += value;
        this.y += value;
    }
};

console.log(o.z);   //返回6

o.z = 2;

console.log(o.z);      //返回20

 

posted @ 2013-12-22 21:08  山贼一名  阅读(227)  评论(0编辑  收藏  举报