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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 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月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
76 2
|
2天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
2天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
2天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
26天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
53 12
|
21天前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
3天前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
|
1月前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
7天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
1月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
41 1
vue学习第一章

推荐镜像

更多