每周分享:彻底弄懂 defineProperty

Vue.js 的流行将其数据双向绑定的核心带到了大家面前,那就是 Object.defineProperty(),在详细讲解这个方法之前,我们先用一段最简单的代码实现一个最简单的数据响应。

<div id="main"></div>
let info = {}
Object.defineProperty(info, 'name', {
  get: function () {
    return document.getElementById('main').innerHTML
  },
  set: function (value) {
    document.getElementById('main').innerHTML = value
  }
})
info.name = "hello" 

这里当我们修改 info.name 的值的时候就会动态反馈到 HTML 元素上。这里的核心就是 set 定义了在给 info 对象设置值的时候会自动去执行 set 中的代码,从而达到了数据绑定的效果。起到了一个触发器的效果。

当然这仅仅是一个简单的示例,实际上 Vue.js 并不是单纯地通过数据和 DOM 节点的绑定来绑定数据,在此之间还有 WacherDirective,这里不细说,接下来主要看看 Object.defineProperty() 到底是什么。

作用

给指定对象加上新的属性或者修改原有属性的值

返回值

被操作的对象

语法

Object.defineProperty(obj, prop, descriptor)

参数

  • obj:要操作的对象
  • prop:要修改或新增的属性名称
  • descriptor:属性描述符

接下来着重讲讲属性描述符

属性描述符

属性描述符(descriptor) 顾名思义就是如何描述(设置)指定属性,分为两种:数据描述符存取描述符

数据描述符

可选键值有

value

要设置的具体值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined

writable

规定该属性是否可被赋值运算符(=)改变。默认为 false

var obj = {}
Object.defineProperty(obj, 'name', {
  value: 'lucy',
  writable: false
})

那么 obj{name: "lucy"},然后我们再修改

obj.name = 'tom'

此时 obj 仍然是 {name: "lucy"} ,因为我们定义了 name 属性的 writablefalse 是不能被赋值运算符修改的(注意这里并不会报错)。当然不设置 writable 的值也是可以的,因为其默认值就是 false

存取描述符

可选键值有

get

一个给属性提供 getter 的方法。当访问该属性时,该方法会被执行,默认为 undefined

set

一个给属性提供 setter 的方法,当属性值修改时,触发执行该方法,默认为 undefined

这俩其实就是在给属性赋值或者取值的时候的一个 触发器

var obj = {}
Object.defineProperty(obj, 'name', {
  set: function (value) {
  },
  get: function () {
  }
})

公共键值

除了上面两种描述符各自独有的键值,他们还有公共的键值可用

configurable

表示该属性是否可以被删除,以及除 writable 特性外的其他特性是否可以被修改。默认为 false

enumerable

定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。默认为 false

var obj = {
  age: 12
}
Object.defineProperty(obj, 'name', {
  value: 'tom',
  enumerable: false
})

这里 obj 变成了 {age: 12, name: "tom"} 但是我们执行

Object.keys(obj)

得到的却是 ["age"] ,可见 enumerable 确实影响到了 Object.keys() 的取值。当然直接写成下面这样也是可以的

Object.defineProperty(obj, 'name', {
  value: 'tom'
})

因为 enumerable 的默认值就是 false

注意,如果同时设置了数据描述符和存取描述符,是会出现异常的,比如我这样写

var obj = {}
Object.defineProperty(obj, 'name', {
  set: function (value) {
  },
  value: 'tom'
})

则会报错

 Invalid property descriptor. Cannot both specify accessors and a value or writable attribute

数据描述符默认值

需要注意的是,以两种不同的方式给属性赋值时,数据描述符中的属性默认值是不同的。

1、点运算

var obj = {}
obj.name = 'tom'

等价于

Object.defineProperty(obj, 'name', {
  value : 'tom',
  writable : true,
  configurable : true,
  enumerable : true
})

2、Object.defineProperty()

Object.defineProperty(obj, 'name', {
  value : 'tom',
})

等价于

Object.defineProperty(obj, 'name', {
  value : 'tom',
  writable : false,
  configurable : false,
  enumerable : false
})

最新评论

  1. This piece of writing is genuinely a nice one it assists new web viewers, who are wishing in favor of blogging. Nicholas Sherief

  2. Hello. This article was really motivating, especially since I was browsing for thoughts on this subject last Sunday. Heriberto Ringen

  3. Piece of writing writing is also a fun, if you be familiar with afterward you can write if not it is complicated to write. Paris Jerabek

  4. I have recently started a site, the information you offer on this site has helped me greatly. Thanks for all of your time & work. Cary Mccombie

发表评论

邮箱地址不会被公开。 必填项已用*标注