美文网首页
Object.defineProperty()及a = 1 和

Object.defineProperty()及a = 1 和

作者: 孤星伴明月 | 来源:发表于2018-11-25 20:48 被阅读0次

本文讨论了js中对象的属性与属性之间的区别。介绍了Object.defineProperty()的用法。

1. 属性与属性的差别

js中的对象是属性的集合。换句话说,js中的对象中什么都没有,只有属性。

虽然同样是对象的属性,其实属性与属性之间还是有很多的区别的。

举个例子:

a = 1;
var b = 2;

如上定义的两个变量有什么区别之处吗? 你可以先思考一下,然后在往下看。

区别之处:

  1. 如果它们写在函数的内部的话,a是不加var就直接定义的全局变量,这种写法已经被鄙视的不行了,因为会导致不可控的全局变量的污染。但并不是不可以使用。b是一个局部变量。以下代码可以证明这一点。
function f(){
    a = 1;
    var b = 2;
}
f();
console.info(a) // 1
console.info(b) // 报错

顺便提一句,如果开启了严格模式,则a=1这中写法就会直接报错了。

"use strict"
function f(){
    a = 1;  // 这里直接报错
    var b = 2;
}
f();
  1. 如果他们写在函数的外部的话,它们都是全局变量,都是加在window对象上的属性。但a属性不能删除,b属性可以删除。
a = 1;
var b = 2;
console.info(window.a)
console.info(window.b)

如果上面的代码并不能正常输出1,2。建议你不要使用chrome浏览器。

下面看下可否删除的例子

a = 1;
var b = 2;
delete window.a // true
delete window.b // false

console.info(window.a); // 无法访问
console.info(window.b); // 还可以访问

同样是属性,为什么一个可以删除,一个不可以? 属性之间地位有差别吗? 答案是:有区别。

我们可以通过Object.getOwnPropertyDescriptor() 来查看这两个属性之间的区别:

a = 1;
var b = 2;
Object.getOwnPropertyDescriptor(window,"a")
//输出:Object { value: 2, writable: true, enumerable: true, configurable: true }
Object.getOwnPropertyDescriptor(window,"b")
//输出:Object { value: 2, writable: true, enumerable: true, configurable: false }

window.a 的 configurable是true
window.b的configurable是false。 这就是区别。

那么其他的三个分别表示:

  • value: 值
  • writable : 是否可以修改
  • enumerable : 是否可以枚举

更详细的说明可以看这里

2. 两种定义对象的属性的方式

  • 初始值/ 赋值
  • Object.defineProperty

1.1 初始值/ 赋值

var obj = {
    name: "fan"
}

这是比较常见的一种做法:对象字面量。

var obj = {}
obj.name = "fan"
// or  obj["name"] = "fan"

这种写法也比较常见。它们产生的效果是一样。

Object.getOwnPropertyDescriptor(obj,"name")

// { value: "fan", writable: true, enumerable: true, configurable: true }

这种方式定义的属性都是:

  • 可删除
  • 可修改
  • 可枚举

1.2 Object.defineProperty

我们可以更加精确地控制属性的特性。例如:让一个属性不能被修改。

使用数据描述符定义对象的属性

var obj = {}; 
Object.defineProperty(obj, 'name', {
  value: 37,
  writable: true,  //如果是false 则不可修改
  enumerable: true,
  configurable: true
});

另一种
使用存取描述符定义对象的属性

var nameValue = "fan";
Object.defineProperty(obj, 'name', {
  get() { return nameValue; },
  set(newValue) {  nameValue = newValue; },
  enumerable: true,
  configurable: true
});

注意,这两种方式不能混在一起使用。 以下代码报错:

var obj = {}
var nameValue = "fan";
Object.defineProperty(obj, 'name', {
  value:"abc",
  get() { return nameValue; },
  set(newValue) { nameValue = newValue; },
  enumerable: true,
  configurable: true
});

报错的内容可能是:

Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object>
at Function.defineProperty (<anonymous>)

3. Object.defineProperty 的应用

3.1 定义特殊的属性,例如只读的

var obj = {}; 
Object.defineProperty(obj, 'name', {
  value: "fan",
  writable: false
});
obj.name = "jake" // 悄悄地失败
console.info(obj.name)  // fan

当然,如果开启了严格模式,就会抛出错误了。

"use strict"
var obj = {}; 
Object.defineProperty(obj, 'name', {
  value: "fan",
  writable: false
});
obj.name = "jake" // 这里会报错
console.info(obj.name)

// Uncaught TypeError: Cannot assign to read only property 'name' of object '#<Object>'

3.2 特殊的属性的处理

在通过存取描述符定义属性时,我们可以在set,get中添加额外的自定义处理逻辑,以达到特殊的效果。

例如:我们希望在给obj.name赋值时,必须是字符串类型,如果是不字符串,就直接报错。

var obj = {}
var nameValue = "fan";
Object.defineProperty(obj, 'name', {
  get() { return nameValue; },
  set(newValue) {
    if((typeof newValue) === "string")
        nameValue = newValue;
    else
        throw new Error("name 必须是字符串...")
      
  },
  enumerable: true,
  configurable: true
});
obj.name = "jake"
console.info(obj.name)  // jake
obj.name = 123 // 报错

以上。

相关文章

网友评论

      本文标题:Object.defineProperty()及a = 1 和

      本文链接:https://www.haomeiwen.com/subject/rjjmqqtx.html