Javascript面向对象(一)——属性标志与描述

Javascript面向对象(一)——属性标志与描述

我们都知道,对象可以存储属性。属性一般都是简单的键值对,但一个对象属性可以更复杂、优美。

属性标志

  • writable – 如果为 true, 属性可以改变,否则为只读。
  • enumerable – 如果为 true, 属性可以在loop…in中被列出,否则不被列出。
  • configurable – 如果为 true, 属性可以被删除或修改,否则不行。

这些属性通常很少使用,使用常规方式创建对象,他们的值都为true,但可以随时改变他们。
首先,看看如何获取他们的值。方法Object.getOwnPropertyDescriptor允许我们查询属性的完整信息。

let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);

其返回值一般称为“属性描述对象”,其包含属性值和所有标志。示例如下:

let user = {
  name: "John"
};

let descriptor = Object.getOwnPropertyDescriptor(user, 'name');

alert( JSON.stringify(descriptor, null, 2 ) );
/* property descriptor:
{
  "value": "John",
  "writable": true,
  "enumerable": true,
  "configurable": true
}
*/

改变标志,可以使用Object.defineProperty,语法如下:

Object.defineProperty(obj, propertyName, descriptor)

如果属性已经存在,则更新标识,否则使用给定的值和属性标识创建。注意:如果没有提供标识,默认为false
示例,这里属性name被创建,所有标识为false

let user = {};

Object.defineProperty(user, "name", {
  value: "John"
});

let descriptor = Object.getOwnPropertyDescriptor(user, 'name');

alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
  "value": "John",
  "writable": false,
  "enumerable": false,
  "configurable": false
}
*/

和正常方式创建对象相比,所有标识为false,如果没有特殊需要,我们最好设置其为true。下面详述每个属性标识。

 只读

我们使user.name只读,通过改变writable标识:

let user = {
  name: "John"
};

Object.defineProperty(user, "name", {
  writable: false
});

user.name = "Pete"; // Error: Cannot assign to read only property 'name'...

现在我们不能修改user对象的name属性值,除非我们使用defineProperty方法覆盖标识。
下面示例效果一样,但对象的属性事前不存在。

let user = { };

Object.defineProperty(user, "name", {
  value: "Pete",
  // for new properties need to explicitly list what's true
  enumerable: true,
  configurable: true
});

alert(user.name); // Pete
user.name = "Alice"; // Error

 非枚举

现在我们user对象增加自定义toString方法。
通常,对象内置的toString方法是非枚举的,使用for..in不会显示,但是如果增加toString方法,则可以通过for..in列出。如果我们不希望被列出,可以使用enumerable:false.则不会被列出,和内置的一样。

let user = {
  name: "John",
  toString() {
    return this.name;
  }
};

// By default, both our properties are listed:
for(let key in user) alert(key); // name, toString

Object.defineProperty(user, "toString", {
  enumerable: false
});

// Now toString disappears:
for(let key in user) alert(key); // name

非枚举属性通过Object.keys方法通用也不能被枚举。

非配置

非配置标识(configurable:false)通常设置在内置对象属性中使用。
非配置标识不能通过defineProperty方法修改或删除。
示例:Math.PI同时是只读、非枚举、非配置:

let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');

alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
  "value": 3.141592653589793,
  "writable": false,
  "enumerable": false,
  "configurable": false
}
*/

所以,开发者不能改变或覆盖他们。

Math.PI = 3; // Error

// delete Math.PI won't work either

使属性为非配置,是单向的,不能改回来。因为defineProperty方法在非配置属性上不工作。
这里我们使user.name用于密封。

let user = { };

Object.defineProperty(user, "name", {
  value: "John",
  writable: false,
  configurable: false
});

// won't be able to change user.name or its flags
// all this won't work:
//   user.name = "Pete"
//   delete user.name
//   defineProperty(user, "name", ...)
Object.defineProperty(user, "name", {writable: true}); // Error

使用严格模式出现错误
在非严格模式下,修改只读属性不会报错。但属性不会改变。强制修改标志在非严格模式下被安静地忽略。

 Object.defineProperties

方法Object.defineProperties(obj,descriptors)允许一次定义多个属性。语法如下:

Object.defineProperties(obj, {
  prop1: descriptor1,
  prop2: descriptor2
  // ...
});

示例:

Object.defineProperties(user, {
  name: { value: "John", writable: false },
  surname: { value: "Smith", writable: false },
  // ...
});

Object.getOwnPropertyDescriptors

使用方法Object.getOwnPropertyDescriptors(obj)方法可以一次性获取多个描述。
Object.defineProperties一起使用,他能够使用“标识感知”的方式克隆对象:

let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));

通常我们克隆对象,使用拷贝属性赋值,代码如下:
for(let key in user) {
clone[key] = user[key]
}
但是,这样并没有拷贝属性,因此要完全克隆,在克隆之前使用Object.defineProperties方法。

全局密封对象

属性描述在在单个属性级别上起作用。也有一些方法实现限制整个对象。

Object.preventExtensions(obj)
禁止给对象增加属性

Object.seal(obj)
禁止增加/删除属性,设置所有存在属性的configurable为false。

Object.freeze(obj)
禁止增加/删除属性,设置所有存在属性的configurable:false, writable: false.

一些测试方法如下:

Object.isExtensible(obj)
Returns false if adding properties is forbidden, otherwise true.

Object.isSealed(obj)
Returns true if adding/removing properties is forbidden, and all existing properties have configurable: false.

Object.isFrozen(obj)
Returns true if adding/removing/changing properties is forbidden, and all current properties are configurable: false, writable: false.

这写方法实际情况很少使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值