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

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

  1. var person = new Object();
  2. person.name = 'Nicy';
  3. person.age = 21;
  4. person.sayName = function() {
  5. console.log(this.name);
  6. };
  7.  
  8. var person = {
  9. name: 'Nicy',
  10. age: 21,
  11. sayName: function() {
  12. console.log(this.name);
  13. }
  14. }

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

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. var person = {};
  2.  
  3. Object.defineProperty(person, "name", {
  4. value: 'Nicy'
  5. })
  6. person.name = 'Lee';  
  7. console.log(person.name) // 'Nicy'
  8.  
  9. Object.defineProperty(person, "name", {
  10. writable: true
  11. })
  12. person.name = 'Lee';
  13. console.log(person.name) // 'Lee'

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

Configurable

  1. var person = {
  2. name: 'Nicy',
  3. age: 21,
  4. sayName: function() {
  5. console.log(this.name);
  6. }
  7. }
  8.  
  9. Object.defineProperty(person, "name", {
  10. configurable: false
  11. })
  12.  
  13. delete person.name; // 操作被忽略,无法通过delete删除属性
  14. Object.defineProperty(person, "name", { // throw error
  15. configurable:true
  16. })
  17. Object.defineProperty(person, "name", { // throw error
  18. enumerable: false
  19. })
  20. Object.defineProperty(person, "name", { // 由于writable为true,所以可以修改value
  21. value: 'Lucy'
  22. })
    console.log(person.name) // Lucy
  23.  
  24. Object.defineProperty(person, "name", { // writable可进行true -> false的单向修改
  25. writable: false
  26. })
  27. Object.defineProperty(person, "name", { // throw error
  28. value: 'Lee'
  29. })
  30. Object.defineProperty(person, "name", { // throw error,此时writable不可以false -> true
  31. writable: true
  32. })

总结一下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. var person = {};
  2. Object.defineProperty(person, "a", { value : 1, enumerable:true });
  3. Object.defineProperty(person, "b", { value : 2, enumerable:false });
  4. Object.defineProperty(person, "c", { value : 3 }); // enumerable defaults to false
  5. person.d = 4; // 如果使用直接赋值的方式创建对象的属性,则这个属性的enumerable默认为true
  6.  
  7. for (var i in person) {
  8. console.log(i);
  9. }  // 'a' 和 'd'
  10.  
  11. Object.keys(person); // ["a", "d"]

访问器属性

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

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

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

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

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

  1. var person = {
  2. name: 'Nicy',
  3. _age: 21,
  4. year: 1997,
  5. _year: 1997,
  6. sayName: function() {
  7. console.log(this.name);
  8. }
  9. }
  10.  
  11. Object.defineProperty(person, "age", {
  12. get: function() {
  13. return this._age;
  14. },
  15. set: function(value) {
  16. this._age = value;
  17. // ...
  18. }
  19. })

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

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

Object.getOwnPropertyDescriptor 读取属性的特性

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

Object.getOwnPropertyDescriptor(obj, prop)

  obj:属性所在的对象;

  prop:要访问的属性名。

数据属性 -> 访问器属性

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

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

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

  1. // 设置get和set其中任意一个即可转换为访问器属性
  2. Object.defineProperty(person, "year", {
  3. get: function() {
  4. // return this,year; // error
  5. return this._year;
  6. },
  7. set: function(value) {
  8. // this.year = value;  // error
  9. this._year= value;
  10. }
  11. })
  12.  
  13. var descriptor = Object.getOwnPropertyDescriptor(person, 'year');
  14. 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. Object.defineProperty(person, "job", {
  2. configurable: true,
  3. enumerable: true,
  4. get: function() {
  5. return this._job;
  6. },
  7. set: function(value) {
  8. this._job = value;
  9. }
  10. })
  11.  
  12. // 设置value和writable其中任意一个即可转换为数据属性
  13. Object.defineProperty(person, "job", {
  14. value: 'worker',
  15. writable: true
  16. })
  17.  
  18. var descriptor = Object.getOwnPropertyDescriptor(person, 'job');
  19. console.log(descriptor); // {value: "worker", writable: true, enumerable: true, configurable: true}

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

Object.defineProperties()

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

  1. var person = {};
  2. Object.defineProperties(person, {
  3. name: {
  4. value: 'Nicy',
  5. writable: true
  6. },
  7. _age: {
  8. value: 21,
  9. enumerable: true,
  10. writable: true,
  11. configurable: true
  12. },
  13. age: {
  14. get: function() {
  15. return this._age;
  16. },
  17. set: function(value) {
  18. this._age = value;
  19. }
  20. }
  21. });

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. Docker入门与应用系列(三)容器管理

    一.启动容器 启动容器有两种方式,一种是基于镜像新建一个容器并启动,另一个是将终止状态的容器重新启动. 1.1 新建并启动 主要命令为 docker run 下面的命令输出一个”Hello,world ...

  2. Centos6.6系统root用户密码恢复案例

    1.重新启动主机后,在出现Grub菜单时按上下键取消倒计时 2.进入到内核引导界面按e键如下所示: 3.将鼠标定位到Kernel这一行按e键 4.在行尾输入”single”也可以换成字母”s”或者数字 ...

  3. vue ESLint自动修复

    在package.json文件中的"lint"里面加入--fix 然后终端里输入:npm run lint 1. vue用命令直接修复ESLint

  4. [USACO09NOV]硬币的游戏A Coin Game

    https://daniu.luogu.org/problemnew/show/P2964 dp[i][j] 表示桌面上还剩i枚硬币时,上一次取走了j个的最大得分 枚举这一次要拿k个,转移到dp[i- ...

  5. Linux Ubuntu下安装配置mysql

    检查系统中是否已经安装了mysql: sudo netstat -tap | grep mysql 安装mysql: sudo apt-get install mysql-server sudo ap ...

  6. javascript的未知尺寸图片保持比例水平垂直居中函数

    JavaScript的图片在容器内水平垂直居中的函数,利用图片加载获取图片大小,使之在父节点内水平垂直居中 展示方式有两种: 1.当参数keepImageFull为true:保持图片比例,使图片可完整 ...

  7. jQuery中下拉框select的操作方法详解

    最近在写页面的时候常常遇到要动态增删改下拉框select的情况,由于我比较习惯用jquery框架来架构我的前端js,所以就顺便把各种jquery操作下拉框select的方法总结了一下,收藏起来以便下次 ...

  8. 20155201 2016-2017-2 《Java程序设计》第六周学习总结

    20155201 2016-2017-2 <Java程序设计>第六周学习总结 教材学习内容总结 第十章 输入/输出 字节输入类: Java将输入/输出抽象化为串流,数据有来源及目的地,衔接 ...

  9. Session详解、ASP.NET核心知识(8)

    介绍一下Session 1.作用 Cookie是存在客户端,Session是存在服务器端,目的是一样的:保存和当前客户端相关的数据(当前网站的任何一个页面都能取到Session). 在本篇博文的姊妹篇 ...

  10. 对于最近一星期jsp培训有感

    这周上课是jsp的培训,找的是外面的一个培训机构的讲师,人挺好的,讲的也不错,不过交给我们的任务是一星期做出一个网站模型——新闻发布系统. 由于我们组本科学计算机的人实在太少了,所以这个重担落在我的身 ...