JavaScript中的Object.defineProperty()

吐槽君 分类:javascript

今天和大家分享下,我们常常听到,但平时项目开发中却很少用的Object.defineProperty()

题目

先上两道开胃题:

  1. if (a=== 1 && a===2 && a===3 ) {}, if可能执行?
  2. 不用const,有什么办法使定义的变量不可变?

Object.defineProperty

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

语法

Object.defineProperty(obj, prop, descriptor)

参数

obj: 要定义属性的对象。
prop: 要定义或修改的属性的名称或 Symbol 。
descriptor: 要定义或修改的属性描述符。

下面要着重讲一下descriptor属性描述对象,该描述对象共有value、configurable、enumerable、value、writable、get、set等6个属性值,

如果一个描述符同时拥有 (value 或 writable) 和 (get 或 set) 键,则会产生一个异常

  1. Value 属性

默认为 undefined, 该属性对应的值

  • 示例
var o = {};
Object.defineProperty(o, "a",{
    value: 1
});
console.log(o.a)  // 1
 

  1. Writable 属性

默认值为false, 代表着它能否被重新赋值

  • 示例
var o = {};
Object.defineProperty(o, "a",{
    value: 1
    writable: false
});
console.log(o.a);  // 1
o.a = 2;  // 抛出异常
console.log(o.a);  // 1
 

上面的问题2,const问题解决。


  1. Enumerable 属性

默认值为false, 代表着它能否被for...in和Object.keys方法中被遍历

  • 示例
var o = {};
Object.defineProperty(o, "a", { value : 1, enumerable: true });
Object.defineProperty(o, "b", { value : 2, enumerable: false });
Object.defineProperty(o, "c", { value : 3 }); // enumerable 默认为 false
o.d = 4; // 如果使用直接赋值的方式创建对象的属性,则 enumerable 为 true
Object.defineProperty(o, Symbol.for('e'), {
  value: 5,
  enumerable: true
});
Object.defineProperty(o, Symbol.for('f'), {
  value: 6,
  enumerable: false
});

for (var i in o) {
  console.log(i);
}
// logs 'a' and 'd' (in undefined order)

Object.keys(o); // ['a', 'd']
Object.getOwnPropertyNames(o);   // ["a", "b", "c", "d"]
Object.getOwnPropertySymbols(o);  // [Symbol(e), Symbol(f)]
Reflect.ownKeys(o);  // ["a", "b", "c", "d", Symbol(e), Symbol(f)]

o.propertyIsEnumerable('a'); // true
o.propertyIsEnumerable('b'); // false
o.propertyIsEnumerable('c'); // false
o.propertyIsEnumerable('d'); // true
o.propertyIsEnumerable(Symbol.for('e')); // true
o.propertyIsEnumerable(Symbol.for('f')); // false

var p = { ...o }
p.a // 1
p.b // undefined
p.c // undefined
p.d // 4
p[Symbol.for('e')] // 5
p[Symbol.for('f')] // undefined
 

上面可以看到,getOwnPropertyNames是可以遍历出所有的非Symbol属性值,无论enumerable是否为false


  1. Configurable 属性

默认为false, 表示该属性的描述符才能够被改变,对象的属性是否可以被删除

  • 示例
var o = {};
Object.defineProperty(o, "a",{
    value: 1,
    configurable: false
});
Object.defineProperty(o, 'a', {
  value: 12
});   // 报错

console.log(o.a)  // 1
o.a = 2;  // // 无效
delete o.a;  // 无效
console.log(o.a)  // 1
 

  • 所以普通定义时:
var o = {};

o.a = 1;
// 等同于:
Object.defineProperty(o, "a", {
  value: 1,
  writable: true,
  configurable: true,
  enumerable: true
});


// 另一方面,
Object.defineProperty(o, "a", { value : 1 });
// 等同于:
Object.defineProperty(o, "a", {
  value: 1,
  writable: false,
  configurable: false,
  enumerable: false
});
 

  1. Get属性

默认值为undefined,当访问该属性时,会调用此函数,该函数的返回值会被用作属性的值

  • 示例
var o = { a: 1 };
Object.defineProperty(o, "a", {
  get: function(){
      console.log("getter");
      return 2
  }
});
console.log(o.a);  // getter,  2
 

  1. Set属性

默认值为undefined,当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值)

  • 示例
var o = { a: 1 };
Object.defineProperty(o, "a", {
  set: function(newValue){
      console.log("setter",newValue);
  }
});
o.a = 2;  // "setter"  2
 

问题:1

var b = 1;  // 避免重复取值定义b
Object.defineProperty(window, "a", {
    get: function(){
        return b++
    }
})
if (a=== 1 && a===2 && a===3 ) {console.log("good")}
 

问题:2

var o = {};
Object.defineProperty(o, "a",{
    value: 1
    writable: false
});
console.log(o.a);  // 1
o.a = 2;  // 抛出异常
console.log(o.a);  // 1
 

Vue2.0中也是通过Object.defineProperty(),在get中进行依赖搜集(Watcher),set中更新订阅派发,具体流程感兴趣可以点这。

回复

我来回复
  • 暂无回复内容