彻底弄懂 defineProperty

Love The Way You Lie 2021-09-18 01:06 629阅读 0赞

彻底弄懂 defineProperty

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

  1. <div id="main"></div>
  2. let info = {}
  3. Object.defineProperty(info, 'name', {
  4. get: function () {
  5. return document.getElementById('main').innerHTML
  6. },
  7. set: function (value) {
  8. document.getElementById('main').innerHTML = value
  9. }
  10. })
  11. info.name = "hello"

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

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

作用

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

返回值

被操作的对象

语法

  1. Object.defineProperty(obj, prop, descriptor)

参数

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

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

属性描述符

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

数据描述符

可选键值有

value

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

writable

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

  1. var obj = {}
  2. Object.defineProperty(obj, 'name', {
  3. value: 'lucy',
  4. writable: false
  5. })

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

  1. obj.name = 'tom'

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

存取描述符

可选键值有

get

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

set

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

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

  1. var obj = {}
  2. Object.defineProperty(obj, 'name', {
  3. set: function (value) {
  4. },
  5. get: function () {
  6. }
  7. })

公共键值

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

configurable

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

enumerable

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

  1. var obj = {
  2. age: 12
  3. }
  4. Object.defineProperty(obj, 'name', {
  5. value: 'tom',
  6. enumerable: false
  7. })

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

  1. Object.keys(obj)

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

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

因为 enumerable 的默认值就是 false

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

  1. var obj = {}
  2. Object.defineProperty(obj, 'name', {
  3. set: function (value) {
  4. },
  5. value: 'tom'
  6. })

则会报错

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

数据描述符默认值

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

1、点运算

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

等价于

  1. Object.defineProperty(obj, 'name', {
  2. value : 'tom',
  3. writable : true,
  4. configurable : true,
  5. enumerable : true
  6. })

2、Object.defineProperty()

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

等价于

  1. Object.defineProperty(obj, 'name', {
  2. value : 'tom',
  3. writable : false,
  4. configurable : false,
  5. enumerable : false
  6. })

发表评论

表情:
评论列表 (有 0 条评论,629人围观)

还没有评论,来说两句吧...

相关阅读

    相关 彻底CSS盒子模式

    前言 如果你想尝试一下不用表格来排版网页,而是用CSS来排版你的网页,也就是常听的用DIV来编排你的网页结构,又或者说你想学习网页标准设计,再或者说你的上司要你改变传统的表格

    相关 彻底JavaScript 执行机制

    很多人在面试的时候都会碰到这么一道面试题:给一段代码,写出执行结果和顺序。其中侧重的知识点可能也不尽相同。写这篇文章,主要是把其中可能涉及到的知识点都简单说一下,自己也好好梳理