Heading for the future

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

 

ECMA-262第5版在定义只有内部才用的特性(attribute)时,描述了属性(property)的各种特征。ECMA-262定义这些特性是为了实现javascript引擎用的,因此在javascript中不能直接访问它们。为了表示特性时内部值,该规范把它们放在了两对方括号中,例如[[Enumerable]]。

数据属性

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

类别

Value

包含这个属性的数据值。读取属性值的时候,从这个位置读取,写入值得时候,把新值保存在这个位置。这个特性得默认值为undefined

Configurable

表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。直接在对象上定义的属性,它们的这个特性默认值为true

Enumerable

表示能否通过for-in循环返回属性,直接在对象上定义的属性,它们的这个特性默认值为true

Writable

表示能否修改属性的值,直接在对象上定义的属性,它们的这个特性默认值为true

修改

要修改默认的特性,必须使用ES5的Object.defineProperty()方法

// 使用方式
Object.defineProperty( obj, prop, descriptor)
obj:需要定义属性的对象。
prop:需定义或修改的属性的名字。
descriptor:一个包含设置特性的对象
// 例子
var person = {name: "percy"};
Object.defineProperty(person,"name",{
  writable: false
});

读取

通过,Object.getOwnPropertyDescriptor()方法获取指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

var girl = {name: "zyj"};
console.log(Object.getOwnPropertyDescriptor(girl,"name"));
// Object {value: "zyj", writable: true, enumerable: true, configurable: true}

注意⚠️

  • 直接在对象上定义的属性,它们的[[Configurable]]、[[Enumerable]]、[[Writable]]特性都被设置为true,[[Value]]特性被设置为了指定的值.

访问器属性

访问器属性不包含数据值,它们包含一对getter和setter函数(这两个函数都不是必须的)。在读取访问器属性时会调用getter函数,这个函数会负责返回有效的值,在写入访问器属性时,会调用setter函数并传入新值。这个函数负责决定如何处理数据。访问器属性有如下4个特性

类别

Configurable

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

Enumerable

表示能否通过for-in循环返回属性。直接在对象上定义的属性,这个特性的默认值为true

Get

在读取属性时调用的函数。默认值为undefined

Set

在写入属性时调用的函数。默认值为undefined

定义

访问器属性不能直接定义,必须使用Object.defineProperty()定义单个或者Object.defineProperties()来定义

定义单个。注意⚠️:用Object.defineProperty()定义的访问器属性,其configurable和enumerable默认为false。

var book = {
    year : 2004,
    edition : 1
};
Object.defineProperty(book,"year",{ 
    get : function () {
        alert(this.year);
    },
    set : function (newValue) {
        if (newValue > 2004) {
            this.year = newValue;
            this.edition += newValue - 2004;
        }
    }
});
book.year;      // 弹出窗口,显示 2004
book.year = 2005;
console.log(book.edition);   // 2

定义多个

var obj = {};
Object.defineProperties(obj, {
  "property1": {
    value: true,
    writable: true
  },
  "property2": {
    value: "Hello",
    writable: false
  }
});

读取

通过,Object.getOwnPropertyDescriptor()方法获取指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

var descriptor = Object.getOwnPropertyDescriptor(girl,"age");
console.log(descriptor.value);         // 22
console.log(descriptor.configurable);  // false
console.log(descriptor.writable);      // true
console.log(descriptor.get);           // undefined
console.log(descriptor.set);           // undefined

注意⚠️

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

数据属性和访问器属性互相转化

数据属性 -> 访问器属性

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

// 设置get和set其中任意一个即可转换为访问器属性
Object.defineProperty(person, "year", {
    get: function() {
        return this._year;    
    },
    set: function(value) {
        this._year= value;
    }
})
var descriptor = Object.getOwnPropertyDescriptor(person, 'year');
console.log(descriptor);    // {get: ƒ, set: ƒ, enumerable: true, configurable: true}

访问器属性 -> 数据属性

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

注意⚠️:可以在访问器属性和数据属性间相互转化的属性其configurable特性值必须为true。configurable为false,则不可以将其转换为数据属性。

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}

扩展:如何定义对象

定义对象一共有如下四种方式

  • 使用语法结构创建的对象
  • 使用构造器创建的对象
  • 使用 Object.create 创建的对象
  • 使用 class 关键字创建的对象

下面我们分别来给个例子🌰

使用语法结构创建对象

var o = {a: 1};

使用构造器创建对象

function Graph() {
  this.vertices = [];
  this.edges = [];
}
var g = new Graph();

使用 Object.create 创建对象

var a = {a: 1}; 
var b = Object.create(a);

使用 class 关键字创建的对象

class Polygon {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}
let polygon = new Polygon();

参考

MDN文档

https://blog.csdn.net/weixin_43936704/article/details/103930693https://www.cnblogs.com/he-ming-min/p/11011402.htmlhttps://www.cnblogs.com/absolute-child/p/7188417.html

https://www.cnblogs.com/shiningly/p/9482283.html?utm_source=debugrun&utm_medium=referral

 

posted @ 2020-08-12 21:35  一只菜鸟攻城狮啊  阅读(594)  评论(0编辑  收藏  举报