详解javascript对象的数据属性与访问器属性


本文摘自PHP中文网,作者青灯夜游,侵删。

创建对象的方式有两种:第一种,通过new操作符后面跟Object构造函数,第二种,对象字面量方式。如下

1

2

3

4

5

6

7

8

9

10

11

12

13

var person = new Object();

person.name = 'Nicy';

person.age = 21;

person.sayName = function() {

    console.log(this.name);

};       

var person = {

    name: 'Nicy',

    age: 21,

    sayName: function() {

        console.log(this.name);

    }

}

这两种方式创建出来的对象是一样的,有相同的属性和方法。这些属性内部都有描述其行为的属性描述符。

Object.defineProperty()

通过Object.defineProperty() 可以直接在对象上创建一个属性,也可以修改已有的属性。

Object.defineProperty(obj, prop, descriptor) 接收三个参数:

  obj:属性所在的对象  

  prop:要访问的属性名

  descriptor:描述符对象

描述符对象包含六个属性:configurable、enumerable、writable、value、get、set ,要修改属性的特性,必须使用Object.defineProperty()方法。

通过以上两种方式添加的对象属性,其布尔值特性默认值是true,通过Object.defineProperty来修改属性特性时,只设置需要修改的特性即可;而通过Object.defineProperty创建的属性,其布尔值特性默认值是false。

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

数据属性

数据属性包含四个属性描述符:

[[Configurable]] : 表示能否通过delete删除属性从而重新定义属性,能否修改属性特性,能否把属性修改为访问器属性。通过以上方式添加的对象属性,默认为true。

[[Enumerable]] : 表示能否通过for-in 循环访问属性。通过以上方式添加的对象属性,默认为true。

[[Writable]] : 表示能否修改属性的值。通过以上方式添加的对象属性,默认为true。

[[Value]] : 包含这个属性的数据值,可读取写入。通过以上方式添加的对象属性,默认为undefined。

Writable

1

2

3

4

5

6

7

8

9

10

11

12

13

var person = {};

 

Object.defineProperty(person, "name", {

    value: 'Nicy'

})

person.name = 'Lee';  

console.log(person.name)    // 'Nicy'

 

Object.defineProperty(person, "name", {

    writable: true

})

person.name = 'Lee';

console.log(person.name)    // 'Lee'

Object.defineProperty直接创建的属性writable默认为false,value值不可修改,此时修改name为Lee,在非严格模式下不会报错,但操作被忽略,在严格模式下会报错。

Configurable

1

<span style="font-size: 13px;"><span style="color: #0000ff;"></span>var person = {<br>    name: 'Nicy',<br>    age: 21,<br>    sayName: function() {<br>        console.log(this.name);<br>    }<br>}<br><br>Object.defineProperty(person, "name", {<br>    configurable: false<br>})<br><br>delete person.name;    // 操作被忽略,无法通过delete删除属性<br>Object.defineProperty(person, "name", {    // throw error<br>    configurable:true    <br>})     <br>Object.defineProperty(person, "name", {    // throw error<br>    enumerable: false<br>})  <br>Object.defineProperty(person, "name", {     // 由于writable为true,所以可以修改value<br>    value: 'Lucy'<br>})console.log(person.name)    // Lucy<br>Object.defineProperty(person, "name", {    // writable可进行true -> false的单向修改<br>    writable: false<br>})<br>Object.defineProperty(person, "name", {     // throw error<br>    value: 'Lee'<br>})<br>Object.defineProperty(person, "name", {    // throw error,此时writable不可以false -> true<br>    writable: true<br>})<span style="color: #000000;"></span></span>

总结一下configurable:当configurable设为false时,

  1、不可以通过delete去删除该属性从而重新定义属性;

  2、不可以转化为访问器属性;

  3、configurable和enumerable不可被修改;

  4、writable可单向修改为false,但不可以由false改为true;

  5、value是否可修改根据writable而定。

当configurable为false时,用delete删除该属性,在非严格模式下,不会报错,但操作被忽略,在严格模式下会报错;其他不可被修改的特性修改时会报错。

Enumerable

enumerable表示对象属性是否可以在for...in和Object.keys()中被枚举。

1

2

3

4

5

6

7

8

9

10

11

var person = {};

Object.defineProperty(person, "a", { value : 1, enumerable:true });

Object.defineProperty(person, "b", { value : 2, enumerable:false });

Object.defineProperty(person, "c", { value : 3 }); // enumerable defaults to false

person.d = 4; // 如果使用直接赋值的方式创建对象的属性,则这个属性的enumerable默认为true

 

for (var i in person) {   

  console.log(i); 

}  //  'a' 和 'd'

 

Object.keys(person); // ["a", "d"]

访问器属性

访问器属性包含四个属性描述符:

[[Configurable]] : 表示能否通过delete删除属性从而重新定义属性,能否修改属性特性,能否把属性修改为数据属性。直接在对象上定义的属性,默认为true。

[[Enumerable]] : 表示能否通过for-in 循环访问属性。直接在对象上定义的属性,默认为true。

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

var person = {

    name: 'Nicy',

    _age: 21,

    year: 1997,

    _year: 1997,

    sayName: function() {

        console.log(this.name);

    }

}

 

Object.defineProperty(person, "age", {

    get: function() {

        return this._age;

    },

    set: function(value) {

        this._age = value;

                // ...

    }

})

用Object.defineProperty()定义的访问器属性,其configurable和enumerable默认为false。

数据属性与访问器属性的相互转换

Object.getOwnPropertyDescriptor 读取属性的特性

使用Object.getOwnPropertyDescriptor可以获取到属性的描述符:

Object.getOwnPropertyDescriptor(obj, prop)

  obj:属性所在的对象;

  prop:要访问的属性名。

数据属性 -> 访问器属性

属性的特性只能是访问器描述符和数据描述符中的一种,给已有的数据属性加get或set转换为访问器属性时,其属性的value、writable就会被废弃。

如下代码,将对象原有的数据属性year转换为访问器属性:

*注:在访问器属性的get和set中,不可以使用this访问属性本身,否则会无限递归而导致内存泄漏。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// 设置get和set其中任意一个即可转换为访问器属性

Object.defineProperty(person, "year", {

    get: function() {

//        return this,year;    // error

        return this._year;   

    },

    set: function(value) {

//             this.year = value;  // error

        this._year= value;

    }

})

 

var descriptor = Object.getOwnPropertyDescriptor(person, 'year');

console.log(descriptor);    // {get: ?, set: ?, enumerable: true, configurable: true}

在原有的数据属性year中,使用Object.defineProperty()为属性设置get 或 set,都可以将其转换为访问器属性。

访问器属性 -> 数据属性

将访问器属性转换为数据属性,只需要给现有访问器属性设置value或writable这两个属性描述符中的任意一个即可,其原有的get和set就会被废弃,从而转换为数据属性。

上面为person定义的访问器属性age,通过Object.defineProperty()只设置了get和set,所以configurable默认为false,不可以将其转换为数据属性。可以在访问器属性和数据属性间相互转化的属性其configurable特性值必须为true。

如下代码,我们为person新定义一个访问器属性job,将其configurable设置为true ,并将其转换为数据属性:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

Object.defineProperty(person, "job", {

    configurable: true,

    enumerable: true,

    get: function() {

        return this._job;

    },

    set: function(value) {

        this._job = value;

    }

})

 

// 设置value和writable其中任意一个即可转换为数据属性       

Object.defineProperty(person, "job", {

    value: 'worker',

    writable: true

})

 

var descriptor = Object.getOwnPropertyDescriptor(person, 'job');

console.log(descriptor);    // {value: "worker", writable: true, enumerable: true, configurable: true}

数据描述符value、writable 和访问器描述符get、set不能同时设置,否则会报错。

Object.defineProperties()

通过Object.defineProperties()可以一次性为对象定义多个属性。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

var person = {};

Object.defineProperties(person, {

  name: {

    value: 'Nicy',

    writable: true

  },

  _age: {

    value: 21,

    enumerable: true,

    writable: true,

    configurable: true

  },

   age: {

    get: function() {

    return this._age;

    },

    set: function(value) {

    this._age = value;

    }

  }

});

相关教程推荐:JavaScript视频教程

以上就是详解javascript对象的数据属性与访问器属性的详细内容,更多文章请关注木庄网络博客

相关阅读 >>

css和javascript之间有什么区别

10个让你效率更高的math对象方法,快来收藏吧!

javascript诞生于哪一年

请描述javascript语言特性有哪些

浅谈javascript之dom核心操作

javascript函数式编程中纯函数的理解(代码)

javascript如何打印

javascript放在什么标签内

javascript继承有哪两种形式

javascript对象和数组的区别是什么

更多相关阅读请进入《javascript》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...