01 - vue源码解析之vue 数据绑定实现的核心 Object.defineProperty()

简介: 01 - vue源码解析之vue 数据绑定实现的核心 Object.defineProperty()

Object.defineProperty() 是啥?


假设我们有个对象user ,我们要给他增加一个name属性 , 我们怎么做 ?

var user = {};
   user.name = "若城"
   console.log(user)

如果要增加一个方法呢 ?

user.sayHi=function(){
      console.log('hi')
     }
  console.log(user)

Object.defineProperty() 就是做这个事情的


如何使用Object.defineProperty()


Object.defineProperty 需要三个参数 (object , propName , descriptor)

  • object 对象 ===》 给谁加
  • propName 属性名 ===》 要加的属性的名字 【类型:Object】
  • descriptor 属性描述 === 》 加的这个属性有什么样的特性【类型:Object】

目前我们知道了基本语法了 , 接下来我们来进行一系列的尝试吧 !!!!!

尝试一 :既然可以给一个对象增加属性 , 那么我们用它来给user 增加一个 name 属性
let user ={}
  Object.defineProperty(user, 'name' , {
      value:'vue 源码之 defineProperty'
    })
    console.log(user)

打印结果

说明那个经典的value 属性依旧是设置属性值的

思考 : 属性值只能是字符串吗? 可不可以是别的属性呢 ?如:number 、 function 、 Object 、 boolean …

尝试二 : 属性值是否可以是除字符串以外的类型


Object.defineProperty(user, 'name',{
    // str
    value:'若城'
  })
  Object.defineProperty(user,'isShow',{
    //  布尔值
    value:true
  })
  Object.defineProperty(user,'handleEat',{
    // 函数
    value:function(){
       console.log('麻辣虾尾')
    }
  })
  Object.defineProperty(user,'age',{
    // num
    value:18
  })
  Object.defineProperty(user,'default',{
    // 对象
     value:{
        hobby:'PLAY',
        birth:'2020-1-1',
        drink:'肥宅快乐水'
     }
  })
  console.log(user)

打印结果

事实证明任何数据类型的数据都是可以的

尝试三 : 如果user对象已经有了 name 属性 , 我们还可以通过 Object.defineProperty 来改变这个值吗?


Object.defineProperty(user,'name',{
     value:'若城'
  })
  user.name="新-若城"
  console.log(user)

我们从打印结果发现,name的值并没有被改变, 为啥嘞??? 我们进行深入的剖析

经查相关资料我们发现, 关于 Object.defineProperty() 他的第三个参数 descriptor 是有很多个参数的 除了 value 属性还有以下属性

  • writable : 属性的值是否可以被重写。设置为true可以被重写;设置为false,不能被重写。默认为false。
  • enumerable: 此属性是否可以被枚举(使用for…in或Object.keys())。设置为true可以被枚举;设置为false,不能被枚举。默认为false。
  • configurable:是否可以删除目标属性或是否可以再次修改属性的特性(writable, configurable, enumerable)。设置为true可以被删除或可以重新设置特性;设置为false,不能被可以被删除或不可以重新设置特性。默认为false。这个属性起到两个作用:1.目标属性是否可以使用delete删除 2.目标属性是否可以再次设置特性

提示:一旦使用Object.defineProperty给对象添加属性,那么如果不设置属性的特性,那么configurable、enumerable、writable这些值都为默认的false

接下来我们进行一次实践:

Object.defineProperty(user,'name',{
     value:'若城',
     writable:true
  })
  user.name="新-若城"
  console.log(user)

完美解决

尝试四:enumerable 【难度升级】

enumerable: 此属性是否可以被枚举(使用for…in或Object.keys())。设置为true可以被枚举;设置为false,不能被枚举。默认为false。

看完enumerable 的解释是不是迷迷糊糊的 , 突然感觉到 3 * 5 = 35 这个 3 * 5 也太难了 ,我们一点点的来解决下

第一点 :假设我们想知道user对象有哪些属性 , 我们一般会这样去做

let user={
    name:'若城',
    age:18,
    hobby:'睡觉'
  }
  // es6
  let keys=Object.keys(user)
  console.log(keys)  // ["name", "age", "hobby"]
  // es5 
  let keys = []
  for (const key in user) {
      keys.push(key)
  }
  console.log(keys)// ["name", "age", "hobby"]

如果我们使用 Object.的方式定义属性会发生什么呢?

let user={
      name:'若城',
      age:18,
      hobby:'睡觉'
    }
    // 定义一个性别, 可以被枚举 
    Object.defineProperty(user,'gender',{
       value:'男',
       enumerable:true
    })
    //  定义一个对象 , 不可以被枚举
    Object.defineProperty(user,'default',{
        value:{
            hobby:'PLAY',
            birth:'2020-1-1',
            drink:'肥宅快乐水'
        },
       enumerable:false
    })
    // es6 
    let keys= Object.keys(user)
    console.log(keys)  //["name", "age", "hobby", "gender"]
    // es5 
    let keys = []
     for (const key in user) {
      keys.push(key)
     }
     console.log(keys)  //["name", "age", "hobby", "gender"]

**通过结果我们发现, enumerable属性值为true 时可以被枚举, 不为true时是不可以被枚举的 **

尝试五: configurable 这个属性有两个作用 1. 属性是否可以被删除  2.属性的特性在第一次设置之后可否被重新定义特性
let user={
        name:'若城',
        age:18
      }
      // 定义一个性别,不可以被删除和重新定义特性
        Object.defineProperty(user, 'gender',{
           value:'男',
           enumerable:true,
           configurable:false
        })
        // 尝试删除 
         delete user.gender
         console.log(user)  //{name: "若城", age: 18, gender: "男"}
        // 重新定义特性
        Object.defineProperty(user,'gender',{
           value:'男',
           enumerable:true,
           configurable:true
        })
        // 报错如下:
        // Uncaught TypeError: Cannot redefine property: gender
       // at Function.defineProperty (<anonymous>)

修改为 可以被删除和重新定义特性试一下

let user={
        name:'若城',
        age:18
      }
 // 定义一个性别,可以被删除和重新定义特性
        Object.defineProperty(user, 'gender',{
           value:'男',
           enumerable:true,
           configurable:true
        })
        // 尝试删除 
        delete user.gender
        console.log(user)  //{name: "若城", age: 18}
        // 重新定义特性
        Object.defineProperty(user,'gender',{
           value:'男',
           enumerable:true,
           configurable:false
        })
        // 删除前
        console.log(user)  //{name: "若城", age: 18, gender: "男"}
        // 删除一下 
        delete user.gender
        console.log(user) //{name: "若城", age: 18, gender: "男"}

configurable设置为 true 则该属性可以被删除和重新定义特性;反之属性是不可以被删除和重新定义特性的,默认值为false

尝试六:set 和 get (即 存取器描述: 定义属性如何被存取)

代码走起


let user = {
       name:'若城'
    }
    let count =12
    // 定义一个age 获取值时返回定义好的变量count
    Object.defineProperty(user , 'age',{
       get :function(){
          return count
       }
    })
    console.log(user.age)

通过代码我们发现 ,在get到该属性的时候我们可以自由发挥值得操作 (比如return 一个表达式 等等 )

接下来我们看下 set

let user= {
       name:'若城'
    }
    var count = 12
    // 定义一个age 获取值时返回定义好的变量Count
    Object.defineProperty(user,'age',{
       get:function(){
         return count
       },
       set: function(newVal){
            count = newVal
       }
    })
    console.log(user.age) //12
    user.age = 123
    console.log(user.age) //123
    console.log(count)   //123

注意

当使用了getter或setter方法,不允许使用writable和value这两个属性(如果使用,会直接报错滴)  

get 是获取值的时候的方法,类型为 function ,获取值的时候会被调用,不设置时为 undefined  

set 是设置值的时候的方法,类型为 function ,设置值的时候会被调用,undefined  

get或set不是必须成对出现,任写其一就可以

写在最后

Object.defineProperty方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象

  • value: 设置属性的值
  • writable: 值是否可以重写。true | false
  • enumerable: 目标属性是否可以被枚举。true | false
  • configurable: 目标属性是否可以被删除或是否可以再次修改特性 true | false
  • set: 目标属性设置值的方法
  • get:目标属性获取值的方法

下期预告 vue3 的 proxy 属性解锁

相关文章
|
4天前
|
机器学习/深度学习 缓存 算法
netty源码解解析(4.0)-25 ByteBuf内存池:PoolArena-PoolChunk
netty源码解解析(4.0)-25 ByteBuf内存池:PoolArena-PoolChunk
|
6天前
|
XML Java 数据格式
深度解析 Spring 源码:从 BeanDefinition 源码探索 Bean 的本质
深度解析 Spring 源码:从 BeanDefinition 源码探索 Bean 的本质
16 3
|
11天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的校园食堂订餐系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的校园食堂订餐系统附带文章源码部署视频讲解等
45 10
|
11天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的校园失物招领网站附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的校园失物招领网站附带文章源码部署视频讲解等
26 9
|
4天前
|
存储 NoSQL 算法
Redis(四):del/unlink 命令源码解析
Redis(四):del/unlink 命令源码解析
|
6天前
|
XML Java 数据格式
深度解析 Spring 源码:揭秘 BeanFactory 之谜
深度解析 Spring 源码:揭秘 BeanFactory 之谜
13 1
|
3天前
|
XML Java 数据格式
Spring容器启动源码解析
Spring容器启动源码解析
|
6天前
|
Java Spring
深入解析Spring源码,揭示JDK动态代理的工作原理。
深入解析Spring源码,揭示JDK动态代理的工作原理。
10 0
|
9月前
|
JavaScript 容器
【Vue源码解析】mustache模板引擎
【Vue源码解析】mustache模板引擎
37 0
|
11月前
|
JavaScript 前端开发
vue源码解析之mustache模板引擎
vue源码解析之mustache模板引擎
72 0

推荐镜像

更多