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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 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 属性解锁

相关文章
|
1月前
|
JavaScript 前端开发 开发者
Vue执行流程及渲染解析
【10月更文挑战第2天】
104 58
|
1月前
|
JavaScript 调度
Vue事件总线(EventBus)使用指南:详细解析与实战应用
Vue事件总线(EventBus)使用指南:详细解析与实战应用
57 1
|
1月前
|
JavaScript UED
Vue双向数据绑定的原理
【10月更文挑战第7天】
|
1月前
|
JavaScript 前端开发 UED
Vue执行流程及渲染解析
【10月更文挑战第5天】
|
1月前
|
移动开发 JavaScript 前端开发
Javaweb之Vue路由的详细解析
Vue.js是一款备受欢迎的前端框架,以其简洁的API和组件化开发模式著称。Vue Router作为其官方路由管理器,在构建单页面应用(SPA)时发挥关键作用,通过URL变化管理组件切换,实现无刷新过渡。本文将详细介绍Vue Router的基础概念、主要功能及使用步骤,帮助JavaWeb开发者快速掌握其工作原理及实践应用。
14 1
|
1月前
|
JSON JavaScript 前端开发
Javaweb中Vue指令的详细解析与应用
Vue指令提供了一种高效、声明式的编码方式,使得开发者可以更专注于数据和业务逻辑,而不是DOM操作的细节。通过熟练使用Vue指令,可以极大地提高开发效率和项目的可维护性。
20 3
|
30天前
|
JavaScript
深入解析:JS与Vue中事件委托(事件代理)的高效实现方法
深入解析:JS与Vue中事件委托(事件代理)的高效实现方法
37 0
|
30天前
|
存储 JavaScript 前端开发
Vue.js项目中全面解析定义全局变量的常用方法与技巧
Vue.js项目中全面解析定义全局变量的常用方法与技巧
39 0
|
1月前
|
缓存 JavaScript API
全面解析 Pinia:Vue 状态管理的新选择
本文深入探讨了 Pinia,作为 Vuex 的替代品,提供了一种更简洁和高效的状态管理方案。文章涵盖了 Pinia 的核心特性,包括支持 Vue2 和 Vue3、TypeScript 支持、无需嵌套模块的设计,以及对同步和异步操作的支持。详细介绍了如何创建和使用 Store,管理状态、Getters 和 Actions,重置状态以及通过 $patch 方法批量更新状态。最后,探讨了如何在不同 Store 之间共享数据和逻辑,为开发者提供了实用的 Pinia 使用指南。
22 0
|
2月前
|
JavaScript 前端开发 UED
Javaweb中Vue指令的详细解析与应用
Vue指令是Vue框架中非常强大的特性之一,它提供了一种简洁、高效的方式来增强HTML元素和组件的功能。通过合理使用这些指令,可以使你的JavaWeb应用更加响应用户的操作,提高交互性和用户体验。而且,通过创建自定义指令,你可以进一步扩展Vue的功能,使其更贴合你的应用需求。
19 1

推荐镜像

更多