Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vue] 87.解释下 Object.defineProperty()方法 #478

Open
qiilee opened this issue Oct 9, 2019 · 0 comments
Open

[vue] 87.解释下 Object.defineProperty()方法 #478

qiilee opened this issue Oct 9, 2019 · 0 comments
Labels

Comments

@qiilee
Copy link
Member

qiilee commented Oct 9, 2019

答案:这是 js 中一个非常重要的方法,ES6 中某些方法的实现依赖于它,VUE 通过它实现双向绑定,此方法会直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象

解析:

语法

Object.defineProperty(object, attribute, descriptor)

  • 这三个参数都是必输项
  • 第一个参数为 目标对象
  • 第二个参数为 需要定义的属性或者方法
  • 第三个参数为 目标属性所拥有的特性

descriptor

前两个参数都很明确,重点是第三个参数 descriptor, 它有以下取值

  • value: 属性的值
  • writable: 属性的值是否可被重写(默认为 false)
  • configurable: 总开关,是否可配置,若为 false, 则其他都为 false(默认为 false)
  • enumerable: 属性是否可被枚举(默认为 false)
  • get: 获取该属性的值时调用
  • set: 重写该属性的值时调用

一个例子

var a = {};
Object.defineProperty(a, "b", {
  value: 123
});
console.log(a.b); //123
a.b = 456;
console.log(a.b); //123
a.c = 110;
for (item in a) {
  console.log(item, a[item]); //c 110
}

因为 writable 和 enumerable 默认值为 false, 所以对 a.b 赋值无效,也无法遍历它

configurable

总开关,是否可配置,设置为 false 后,就不能再设置了,否则报错, 例子

var a = {};
Object.defineProperty(a, "b", {
  configurable: false
});
Object.defineProperty(a, "b", {
  configurable: true
});
//error: Uncaught TypeError: Cannot redefine property: b

writable

是否可重写

var a = {};
Object.defineProperty(a, "b", {
  value: 123,
  writable: false
});
console.log(a.b); // 打印 123
a.b = 25; // 没有错误抛出(在严格模式下会抛出,即使之前已经有相同的值)
console.log(a.b); // 打印 123, 赋值不起作用。

enumerable

属性特性 enumerable 定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举

var a = {};
Object.defineProperty(a, "b", {
  value: 3445,
  enumerable: true
});
console.log(Object.keys(a)); // 打印["b"]

enumerable 改为 false

var a = {};
Object.defineProperty(a, "b", {
  value: 3445,
  enumerable: false //注意咯这里改了
});
console.log(Object.keys(a)); // 打印[]

set 和 get

如果设置了 set 或 get, 就不能设置 writable 和 value 中的任何一个,否则报错

var a = {};
Object.defineProperty(a, "abc", {
  value: 123,
  get: function() {
    return value;
  }
});
//Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object> at Function.defineProperty

对目标对象的目标属性 赋值和取值 时, 分别触发 set 和 get 方法

var a = {};
var b = 1;
Object.defineProperty(a, "b", {
  set: function(newValue) {
    b = 99;
    console.log("你要赋值给我,我的新值是" + newValue);
  },
  get: function() {
    console.log("你取我的值");
    return 2; //注意这里,我硬编码返回2
  }
});
a.b = 1; //打印 你要赋值给我,我的新值是1
console.log(b); //打印 99
console.log(a.b); //打印 你取我的值
//打印 2    注意这里,和我的硬编码相同的

上面的代码中,给 a.b 赋值,b 的值也跟着改变了。原因是给 a.b 赋值,自动调用了 set 方法,在 set 方法中改变了 b 的值。vue 双向绑定的原理就是这个。

扩展:参考

@qiilee qiilee added the VUE label Oct 9, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant