Object函数的内置方法 Object.defineProperty

一、定义

Object.defineProperty()方法用于在对象上定义或修改一个自有属性,并返回这个对象。

二、语法

Object.defineProperty(obj, prop, descriptor)

参数:

obj:要定义或修改属性的对象

prop:属性字符串名

descriptor:属性描述符对象

返回值:

被传递给函数的对象

三、属性描述符

对象的属性的属性描述符主要有两种形式,分别是数据描述符和存取描述符。

数据描述符是一个具有值的属性。

存取描述符是由getter和setter函数描述的属性。

 

数据描述符具有的键值:

configurable:可配置性。当该特性为true时,属性描述符可以被修改,属性可以被删除。默认为false。

enumerable:可枚举性。当该特性为true时,属性可以出现在对象的枚举属性中。默认为false。

writable:可写性。当该特性为true时,属性的值可以被赋值运算符改变。默认为false。

value:属性对应的值。可以是任意有效的JavaScript值。默认为undefined。

存取描述符具有的键值:

configurable:可配置性。当该特性为true时,属性描述符可以被修改,属性可以被删除。默认为false。

enumerable:可枚举性。当该特性为true时,属性可以出现在对象的枚举属性中。默认为false。

get:一个给属性提供getter的方法。如果没有getter则默认为undefined,属性将不可读。

set:一个给属性提供setter的方法。如果没有setter则默认为undefined,属性将不可以修改。

如果一个属性描述符不具有value、writable、set和get的任意一个关键字,则认为是一个数据描述符。

四、示例

示例1:定义一个数据属性

var obj = Object.defineProperty({}, 'a', {
    value: 1
});

Object.getOwnPropertyDescriptor(obj, 'a');
// {value: 1, writable: false, enumerable: false, configurable: false}

obj.b = 2;
Object.getOwnPropertyDescriptor(obj, 'b');
// {value: 2, writable: true, enumerable: true, configurable: true}

通过Object.defineProperty()方法定义的数据属性,如果没有指定writable、enumerable、configurable特性,则这三个特性默认为false。

通过表达式直接创建的属性(b),默认是数据属性,且writable、enumerable、configurable特性,则这三个特性默认为true。

示例2:定义一个存取属性

var obj = { x: 1 };
Object.defineProperty(obj, 'a', {
    get: function () { return this.x;},
    set: function (val) { this.x = val;}
});
Object.getOwnPropertyDescriptor(obj, 'a');
// {get: ƒ, set: ƒ, enumerable: false, configurable: false}

通过Object.defineProperty()方法定义的存取属性,如果没有指定enumerable、configurable特性,则这两个特性默认为false。

示例3:数据属性的特性功能示例

// 创建一个空对象
var obj = {};

// 定义一个可写的、不可枚举的、可配置的属性x
Object.defineProperty(obj, 'x', {
    value: 1,
    writable: true,
    enumerable: false,
    configurable: true
});

// 访问对象的属性
obj.x; // 1,说明属性是存在的

// 枚举对象的属性,获取不到属性x
Object.keys(obj); // []

// 修改属性的可写性,使其变为只读
Object.defineProperty(obj, 'x', { writable: false });

// 尝试修改属性的值
obj.x = 2;
obj.x; // 1, 静默修改失败,在严格模式下引发TypeError异常。

// 目前属性是可配置的,故可以通过defineProperty来修改属性的值
Object.defineProperty(obj, 'x', { value: 2 });
obj.x;  // 2 属性值修改成功

// 将属性可写性改回可写
Object.defineProperty(obj, 'x', { writable: true });

// 将属性可配置性改成不可配置
Object.defineProperty(obj, 'x', { configurable: false });

// 此时,可以修改对象属性的值,但不能修改对象属性的可枚举性和可配置性,强行修改会引发TypeError
// 但此时,依然可以把对象属性的可写性改回不可写
Object.defineProperty(obj, 'x', { writable: false });

// 自从之后,对象的属性x,不可配置、不可修改、不可枚举、不可删除。

如果configurable为false,不可修改enumerable和configurable,但可以把writable从true改为false,无法把writable从false改为true。

如果configurable为true,writable为false,只能通过Object.defineProperty()方法来修改属性的值。

示例4:存取属性的特性功能演示

var obj = {};
obj.a = 1;
obj.b = 2;
Object.defineProperty(obj, 'c', {
    get: function () {
        return Math.sqrt(obj.a * obj.a + obj.b * obj.b);
    },
    set: function (value) {
        obj.a = value;
    }
});

Object.getOwnPropertyDescriptor(obj, 'c');
// {get: ƒ, set: ƒ, enumerable: false, configurable: false}
// 由于在定义属性c的时候没有显式指定enumerable和configurable的值,故这2个特性默认为false。
// 此时不能修改其getter和setter方法。

// 尝试修改为数据属性
Object.defineProperty(obj, 'c', { value: 3 });
// 上述操作会引发TypeError:Cannot redefine property: c

如果存取属性是不可配置的,则不能修改其getter和setter方法,也不能将其转换为数据属性。

示例5:数据属性和存取属性的转换

var obj = {};
// 定义一个可写、可配置、可枚举的数据属性
Object.defineProperty(obj, 'a', {
    value: 1,
    writable: true,
    enumerable: true,
    configurable: true
});

Object.getOwnPropertyDescriptor(obj, 'a');
// {value: 1, writable: true, enumerable: true, configurable: true}

obj.a; // 1

// 转换为存取属性
Object.defineProperty(obj, 'a', {
    get: function () { 
        console.log('get a');
        return 2; 
    }
});

Object.getOwnPropertyDescriptor(obj, 'a');
// {get: ƒ, set: undefined, enumerable: true, configurable: true}

obj.a; // 'get a', 2

// 再转回数据属性
Object.defineProperty(obj, 'a', {
    value: 3
});

obj.a; // 3

如果属性是可配置的,则可以从数据属性转为存取属性,也可以从存取属性转为数据属性。

posted @ 2022-03-29 16:46  之鹿喵  阅读(157)  评论(0编辑  收藏  举报