JavaScript对象以及属性

203 阅读4分钟

ECMA-262把对象定义为:“无序属性的集合,其属性可以包含基本值、对象或者函数。”

创建对象

  1. 传建一个 Object 实例,然后添加属性和方法。

    var person = new Object();
    person.name = "Zhang San";
    person.age = 20;
    person.sayName = function() {
    	alert(this.name);
    }
    

    上面的例子创建了一个名为 person 的对象,并为它添加了两个属性(name、age)和一个 方法(sayName())。其中,sayName()方法用于显示 this.name(将被解析为 person.name)的值。

  2. 对象字面量

    前面的例子可以用可以写成这样:

    var person = {
    	name: "Zhang San",
    	age: 20,
    	
    	sayName: function(){
    		alert(this.name);
    	}
    }
    

属性类型

ECMA-262定义了一些用来描述属性各种特征的特性。这些特性是为了实现 JavaScript 引擎用的,因此不能直接访问这些特性。为了表示特性是内部值,该规范把它们放在了两对方括号中,例如:[[Enumerable]]

ECMAScript中有两种属性:数据属性和访问器属性。

数据属性

数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有四个描述其行为的特性。

特性 描述 默认值
Configurable 表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。 true
Enumerable 表示能否通过 for-in 循环返回属性 true
Writable 表示能否修改属性的值 true
Value 包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。 undefined

当直接在对象上定义的属性:

var person = {
	name: "Zhang San"
}

这里创建了一个名为 name 的属性,为它指定的值是"Nicholas"。也就是说,[[Value]] 特性将 被设置为"Nicholas",而对这个值的任何修改都将反映在这个位置。

要修改属性默认的特性,必须使用 ECMAScript 5 的 Object.defineProperty() 方法。这个方法接受三个参数:属性所在的对象,属性的名字以及一个描述对象。

var person = {
	name: "Zhang San"
}
Object.defineProperty(person, 'name', {
 writable: false,
    value: 'zjl'
})

person.name = 'yyq';
console.log(person.name);  // zjl

Object.defineProperty(person, 'name', {
    configurable: false
})

delete person.name;
console.log(person.name);  // zjl

把 configurable 设置为 false,表示不能从对象中删除属性。如果对这个属性调用 delete,则 在非严格模式下什么也不会发生,而在严格模式下会导致错误。而且,一旦把属性定义为不可配置的, 就不能再把它变回可配置了。

例如,对上面的对象在重新设置 [[writeable] ]特性将出现报错:

Object.defineProperty(person, 'name', {
    writable: true
})
Object.defineProperty(person, 'name', {
       ^

TypeError: Cannot redefine property: name
...
访问器属性

访问器属性不包含数据值;它们包含一对 gettersetter 函数(不过,这两个函数都不是必需的)。

在读取访问器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入访问器属性时,会调用 setter 函数并传入新值,这个函数负责决定如何处理数据。访问器属性有如下 4 个特性。

特性 描述 默认值
Configurable 表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特 性,或者能否把属性修改为数据属性。 true
Enumerable 表示能否通过 for-in 循环返回属性。 true
Get 在读取属性时调用的函数。 undefined
Set 在写入属性时调用的函数。 undefined

看到这里,你也许会有疑惑,那类似于上面用对象字面量定义的对象,其属性是什么属性呢?答案是:数据属性。因为,访问器属性不能直接定义,必须使用 Object.defineProperty()来定义。

var person = {
    _firstName: "Zhang",
    _lastName: "San"
}

Object.defineProperty(person, 'name', {
    get: function() {
        return this._firstName + ' ' + this._lastName;
    },

    set: function(lastName) {
        this._lastName = lastName;
        console.log('Congratulations!!!');
    }
})

console.log(person.name); //Zhang San
person.name = 'Jialu';    //Congratulations!!!
console.log(person.name); //Zhang Jialu

以上代码创建了一个对象,并给它定义了两个默认的属性:_firstName_lastName。前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性。而访问器属性 year 则包含一个 getter 函数和一个 setter 函数。

不一定非要同时指定 getter 和 setter。只指定 getter 意味着属性是不能写,尝试写入属性会被忽略。 在严格模式下,尝试写入只指定了 getter 函数的属性会抛出错误。类似地,只指定 setter 函数的属性也 不能读,否则在非严格模式下会返回 undefined,而在严格模式下会抛出错误。

兼容性:

支持 ECMAScript 5 的这个方法的浏览器有 IE9+(IE8 只是部分实现)、Firefox 4+、Safari 5+、Opera 12+和 Chrome。在这个方法之前,要创建访问器属性,一般都使用两个非标准的方法: __defineGetter__()__defineSetter__()

person.__defineGetter__("name", function() {
    return this._firstName + ' ' + this._lastName;
})
person.__defineSetter__("name", function(lastName) {