使用Object.defineProperty进行数据劫持,实现响应式原理-剖析vue2.0

使用Object.defineProperty进行数据劫持,实现响应式原理-剖析vue2.0数据响应式是 vue 的特性之一 在面试过程中也会常常被问起响应式原理 现在就让我们深入了解一下 vue2 0 中如何实现响应式 下图是 Vue2 0 中对响应式原理的描述 其核心就是使用 Object defineProper 中的 get set 进行数据劫持 虽然 Vue3 0 中使用 Proxy 代理 去实现响应式 其实原理都差不多 在 3 0 中主要是使用 Proxy 的 get 和 set 实现响应式 如果理解 defineProper Proxy 也会很快理解的 Object defineProper 是什么

数据响应式是vue的特性之一,在面试过程中也会常常被问起响应式原理,现在就让我们深入了解一下vue2.0中如何实现响应式,

在这里插入图片描述

Object.defineProperty是什么?

let object1={ 
    property1:0 } //例如 Object.defineProperty(object1, 'property1', { 
    value: 42, writable: false, //是否可写 configurable: false, //是否可删除 enumerable: false, //是否可枚举(遍历) }); //get set配置项 Object.defineProperty(object1, 'property1', { 
    get() { 
   //get方法在进行获取的时候触发 return property1 }, set(newVal) { 
   //get方法在进行设置的时候触发,主要在此实现数据劫持 property1 = newVal } }); //我这边常用一种复数形式Object.defineProperties Object.defineProperties(object1, { 
    property1: { 
    get() { 
    //get方法在进行获取的时候触发 return property1 }, set(newVal) { 
    //get方法在进行设置的时候触发,主要在此实现数据劫持 property1 = newVal } } }) 

使用上述的内容实现Vue2.0中的双向绑定

实现出来的效果

在这里插入图片描述

html部分

 
    DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>响应式计算器 
      title> <style> .btnGroup > button.active{ 
        background-color: orange; color: #fff; }  
       style>  
        head> <body> <div id="computed"> <div class="result">0 
         div> <div class="inputGroup"> <input type="number" class="ipt1" value="0" /> <br/> <input type="number" class="ipt2" value="0" />  
          div> <div class="btnGroup"> <button data-field="add" class="active">+ 
           button> <button data-field="sub">- 
            button> <button data-field="mul">* 
             button> <button data-field="div">/ 
              button>  
               div>  
                div>  
                <script src="./js/index.js"> 
                 script>  
                  body>  
                   html> 

js部分

class Arithmetic { 
    //定义算法类 add(a, b) { 
    return a + b } sub(a, b) { 
    return a - b } mul(a, b) { 
    return a * b } div(a, b) { 
    return a / b } } class Computed extends Arithmetic { 
    constructor() { 
    super(); this.result = document.getElementsByClassName('result')[0]; //获取结果dom this.ipt1 = document.getElementsByClassName('ipt1')[0]; //获取输入框 this.ipt2 = document.getElementsByClassName('ipt2')[0]; this.btnGroup = document.getElementsByClassName('btnGroup')[0]; this.btnItems = this.btnGroup.getElementsByTagName('button'); this.data = this.defineData(); this.btnIndex = 0; //记录选中btn索引 } // 1.进行初始化 init() { 
    this.bindEvent(); } // 2.绑定事件 bindEvent() { 
    this.btnGroup.addEventListener('click', this.onFieldBtnClick.bind(this), false) this.ipt1.addEventListener('input', this.onNumberIpt.bind(this), false) this.ipt2.addEventListener('input', this.onNumberIpt.bind(this), false) } // 6.使用Object.defineProperty进行数据劫持 defineData() { 
    let _obj = { 
   }, field = 'add', //保存计算方法字段 fNumber = 0, //inp1的value sNumber = 0; //inp2的value let that = this; // 进行数据劫持 Object.defineProperties(_obj, { 
    fNumber: { 
    get() { 
    return fNumber }, set(newVal) { 
    fNumber = newVal // 重点:在fNumber改变之后计算结果,此处vue使用的是Dom diff算法 that.computedResult(fNumber, sNumber, field); } }, sNumber: { 
    get() { 
    return sNumber }, set(newVal) { 
    sNumber = newVal that.computedResult(fNumber, sNumber, field); } }, field: { 
    get() { 
    return field }, set(newVal) { 
    field = newVal that.computedResult(fNumber, sNumber, field); } } }) return _obj } // 3.btn点击事件 onFieldBtnClick(ev) { 
    let e = ev || window.event, tar = e.target || e.srcElement, tarName = tar.tagName.toLowerCase(); tarName === 'button' && this.update(tar); } // 4.btn进行选项卡切换并更改field update(target) { 
    this.btnItems[this.btnIndex].className = ''; this.btnIndex = [].indexOf.call(this.btnItems, target); target.className += ' active'; this.data.field = target.getAttribute('data-field'); } // 5.ipt改变(input)事件 onNumberIpt(ev) { 
    let e = ev || window.event, tar = e.target || e.srcElement, className = tar.className, val = Number(tar.value.replace(/\s+/g, '')) || 0; //去除input的空格 switch (className) { 
    case 'ipt1': // 改变fNumber触发set()将重新计算结果 this.data.fNumber = val; break; case 'ipt2': // 改变sNumber触发set()将重新计算结果 this.data.sNumber = val; break; default: break; } } // 7.使用继承算法类的方法进行结果计算 computedResult(fNumber, sNumber, field) { 
    this.result.innerHTML = this[field](fNumber, sNumber) } } new Computed().init(); 

往期精彩文章

  • 一篇文章带你揭秘现代浏览器原理
  • 带你深入理解什么叫js闭包
  • 前端性能优化之rel=“prefetch“预/懒加载功能
  • 前端唤起相机的方法H5+JS
  • docker下YApi部署教程-支持swagger数据导入
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/204874.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午7:20
下一篇 2026年3月19日 下午7:20


相关推荐

发表回复

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

关注全栈程序员社区公众号