此文为转载,原文: 深入理解对象的数据属性与访问器属性

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

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

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

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

总结一下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()中被枚举。

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。

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访问属性本身,否则会无限递归而导致内存泄漏。

// 设置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 ,并将其转换为数据属性:

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()可以一次性为对象定义多个属性。

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;
}
}
});

js对象的属性:数据(data)属性和访问器(accessor)属性的更多相关文章

  1. 利用js对象将iframe数据缓存, 实现子页面跳转后, 返回时不丢失之前填写的数据

    利用js对象将iframe数据缓存, 实现子页面跳转后, 返回时不丢失之前填写的数据 实现描述:将数据存放在js对象中, 然后放在父页面的document对象中, 在页面刷新的时候将父页面的值取出来, ...

  2. JavaScript 属性类型(数据属性和访问器属性)

    数据属性 数据属性包含一个数据值的位置.在这个位置可以读取和写入值.数据属性有 4 个描述其行为的特性. [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修 ...

  3. WCF服务中,[DataMember]属性标记的属性一定要有set访问器

    WCF服务中,如果实体类中,包含有[DataMember]属性标记时,该属性一定要有set访问器.当系统必须调用到[DataMember]标记的属性时,如果该属性没有set访问器,则会出错.

  4. Vue之挂载点、变量、事件、js对象、文本指令、过滤器、事件指令和属性指令

    1.vue导入-挂载点 <!DOCTYPE html> <html lang="zh"> <head> <meta charset=&qu ...

  5. js 对象方法、类方法、原型方法的区别;私有属性、公有属性、公有静态属性的区别

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  6. js中属性类型:数据属性与访问器属性

    js中属性类型分为两种:数据属性和访问器属性 在js中,对象都是由名值对构成的,名:就是我们所说的属性名,值就是属性对应的值(基本值.对象.方法). ECMA-262第5版定义了只有内部才用的特性,描 ...

  7. 关于get和set访问器以及属性和字段变量的区别问题

    属性是对一个或者多个字段的封装.      类里面为什么要用一个共有的属性来封装其中的字段,也可以这样说用共有属性来封装私有变量,其中的好处应该大家都说的出来,就是为了实现数据的封装和保证了数据的安全 ...

  8. Vue.js 源码分析(七) 基础篇 侦听器 watch属性详解

    先来看看官网的介绍: 官网介绍的很好理解了,也就是监听一个数据的变化,当该数据变化时执行我们的watch方法,watch选项是一个对象,键为需要观察的数据名,值为一个表达式(函数),还可以是一个对象, ...

  9. JS的数据属性和访问器属性

    ECMA-262第5版在定义只有内部才用的特性(attribute)时,描述了属性(property)的各种特征.ECMA-262定义这些特性是为了实现javascript引擎用的,因此在javasc ...

随机推荐

  1. Chapter 6(树)

    1.树的储存方式 //****************双亲表示法************************ #define Max_TREE_SIZE 100 typedef int TElem ...

  2. 一些程序OEP入口特征

    声明: 1.本文中使用的例子来源于吾爱破解的官方教程第一课中的无壳例子,本人利用空闲时间挨个进行查看并截图纪录下来 2.欢迎补充讨论 一些程序OEP入口特征 一.       AMS程序 1.载入PE ...

  3. P2776 [SDOI2007]小组队列

    P2776 [SDOI2007]小组队列 题目背景 嘛,这道非常简单的给大家提供信心的省选题洛谷居然没有! 这么简单的题怎么可以没有! 给大家提升士气是义不容辞的责任! 所以我就来补一下啦.. 值得一 ...

  4. linux下sudo命令

    [userld@redhat2 root]$ sudo ls We trust you have received the usual lecture from the local System Ad ...

  5. Jekins - Hello world,Jekins + Maven + Git + Tomcat 的简单应用

    Java Web 工程 新建一个简单的 Java Web 工程,并提交至 GitHub,可参考 Eclipse 提交工程至 GitHub 下载 jekins.war 在 http://mirrors. ...

  6. Redis实战(三)CentOS 7上Redis主从复制

    一主二从架构 1.一主二从架构图 2.通过命令 mkdir redisCluster创建redis集群文件夹 3.通过命令mkdir 6380   mkdir 6381   mkdir 6382在re ...

  7. bzoj 1044 [HAOI2008]木棍分割(二分+贪心,DP+优化)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1044 [题意] n根木棍拼到一起,最多可以切m刀,问切成后最大段的最小值及其方案数. ...

  8. Java 对象初始化生命周期

    class Man { String name; int age = 20; public static int sex = 1; Man(String name, int age) { //supe ...

  9. vuex的安装

    可以启动vue ui 手动添加vuex. 或使用 cnpm install vuex 2.使用,import vuex from “vuex” vue.use(vuex) 3.安装插件, 首先键入谷歌 ...

  10. Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A

    问题: 当我们打开数据库,即use dbname时,要预读数据库信息,当使用-A参数时,就不预读数据库信息. 解决方法:mysql -hhostname -uusername -ppassword - ...