vue中defineProperty和Proxy的区别详解


Posted in Vue.js onNovember 30, 2020

Proxy的出现,给vue响应式带来了极大的便利,比如可以直接劫持数组、对象的改变,可以直接添加对象属性,但是兼容性可能会有些问题

Proxy可以劫持的数组的改变,defineProperty 需要变异

defineProperty 中劫持数组变化的变异的方法

可以理解为在数组实例和原型之间,插入了一个新的原型的对象,这个原型方法实现了变异的方法,也就真正地拦截了数组原型上的方法

我们来看下vue2.x的源码

// vue 2.5.0
var arrayProto = Array.prototype;
var arrayMethods = Object.create(arrayProto); // Array {}
function def(obj, key, val, enumerable) {
  Object.defineProperty(obj, key, {
   value: val,
   enumerable: !!enumerable,
   writable: true,
   configurable: true
  });
}
var methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
  ];

  /**
  * Intercept mutating methods and emit events
  */
  methodsToPatch.forEach(function(method) {
  // cache original method
  var original = arrayProto[method]; 
    // 比如 method是push,则结果为
    // ƒ push() { [native code] }
  def(arrayMethods, method, function mutator() {
   var args = [],
   len = arguments.length;
   while (len--) args[len] = arguments[len];

   var result = original.apply(this, args);
   var ob = this.__ob__;
   var inserted;
   switch (method) {
   case 'push':
   case 'unshift':
    inserted = args;
    break
   case 'splice':
    inserted = args.slice(2);
    break
   }
   if (inserted) {
   ob.observeArray(inserted);
   }
   // notify change
   ob.dep.notify();
   return result
  });
  });
  
  /**
  * Observe a list of Array items.
  */
  Observer.prototype.observeArray = function observeArray(items) {
  for (var i = 0, l = items.length; i < l; i++) {
   observe(items[i]); // 后续的逻辑
  }
  };

Proxy可以直接劫持数组的改变

let proxy = new Proxy(fruit, {
    get: function (obj, prop) {
      return prop in obj ? obj[prop] : undefined

    },
    set: function (obj, prop, newVal) {
      obj[prop] = newVal
      console.log("newVal", newVal) // 输出{ name: "lemon", num: 999 }
      return true;
    }
  })
  proxy.push({ name: "lemon", num: 999 })
  console.log(fruit)

vue中defineProperty和Proxy的区别详解

Proxy代理可以劫持对象的改变,defineProperty需要遍历

defineProperty

let fruit = {
     "apple": 2,
     "pear": 22,
     "peach": 222
  }
  Object.keys(fruit).forEach(function (key) {
      Object.defineProperty(fruit[i], key, {
        enumerable: true,
        configurable: true,
        get: function () {
          return val;

        },
        set: function (newVal) {
          val = newVal; // 输出 newVal 888
          console.log("newVal", newVal)
        }
      })
    })
   fruit.apple = 888

Proxy

let fruit = {
     "apple": 2,
     "pear": 22,
     "peach": 222
  }
  let proxy = new Proxy(fruit, {
    get: function (obj, prop) {
      return prop in obj ? obj[prop] : undefined

    },
    set: function (obj, prop, newVal) {
      obj[prop] = newVal
      console.log("newVal", newVal) // 输出 newVal 888
      return true;
    }
  })
  proxy.apple = 888

Proxy代理可以劫持对象属性的添加,defineProperty用this.$set来实现
defineProperty,如果属性不存在,则需要借助this.$set

<div id="app">
  <span v-for="(value,name) in fruit">{{name}}:{{value}}个 </span> 
  <button @click="add()">添加柠檬</button>
</div>
<script src="https://unpkg.com/vue"></script>
<script>
  new Vue({
    el: '#app',
    data() {
      return {
        fruit: {
          apple: 1, 
          banana: 4, 
          orange: 5 
        }
      }
    },

    methods: {
      add() {
          this.fruit.lemon = 5;  // 不会让视图发生变化
        // this.$set(this.fruit,"lemon",5)  // this.$set可以
      }
    }
  })
</script>
Object.keys(fruit).forEach(function (key) {
    Object.defineProperty(fruit, key, {
      enumerable: true,
      configurable: true,
      get: function () {
        return val;

      },
      set: function (newVal) {
        val = newVal;
        console.log("newVal", newVal) // 根本没有进去这里
      }
    })
  })

Proxy 直接可以添加属性

// vue 3
<div id="app">
  <span v-for="(value,name) in fruit">{{name}}:{{value}}个 </span>
  <button @click="add()">添加柠檬</button>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
  Vue.createApp({
    data() {
      return {
        fruit: {
          apple: 1,
          banana: 4,
          orange: 5
        }
      }
    },

    methods: {
      add() {
        this.fruit.lemon = 5; // 这样子是可以的
      }
    }
  }).mount('#app') // vue 3 不再是使用el属性,而是使用mount
</script>
let proxy = new Proxy(fruit, {
    get: function (obj, prop) {
      return prop in obj ? obj[prop] : undefined

    },
    set: function (obj, prop, newVal) {
      obj[prop] = newVal
      console.log("newVal", newVal) // lemon, 888
      return true;
    }
  })
  proxy.lemon = 888

Proxy

其他属性

vue中defineProperty和Proxy的区别详解

应用场景 promisify化

用Proxy写一个场景,请求都是通过回调,如果我们需要用promise包一层的话,则可以

// server.js
// 假设这里都是回调
export const searchResultList = function (data, callback, errorCallback) {
 axios.post(url, data, callback, errorCallback)
}
// promisify.js
import * as server from './server.js'
const promisify = (name,obj) => (option) => {
 return new Promise((resolve, reject) => {
  return obj[name](
   option,
   resolve,
   reject,
  )
 })
}
const serverPromisify = new Proxy(server, {
 get (target,prop) {
  return promisify(prop, server)
 }
})
export default serverPromisify

使用

// index.js
import serverPromisify from './serverPromisify'
serverPromisify.searchResultList(data).then(res=>{

})

如有不正确,望请指出

vue中defineProperty和Proxy的区别详解

留下一个疑问,既然兼容性不是很好,那么尤大是怎么处理polyfill呢

 到此这篇关于vue中defineProperty和Proxy的区别详解的文章就介绍到这了,更多相关vue defineProperty和Proxy内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Vue.js 相关文章推荐
vuex的数据渲染与修改浅析
Nov 26 Vue.js
详解Vue 的异常处理机制
Nov 30 Vue.js
详解vue中使用transition和animation的实例代码
Dec 12 Vue.js
vue实现登录、注册、退出、跳转等功能
Dec 23 Vue.js
vue登录页实现使用cookie记住7天密码功能的方法
Feb 18 Vue.js
Vue实现todo应用的示例
Feb 20 Vue.js
vue 使用 v-model 双向绑定父子组件的值遇见的问题及解决方案
Mar 01 Vue.js
vue3使用vue-router的完整步骤记录
Jun 20 Vue.js
前端vue+express实现文件的上传下载示例
Feb 18 Vue.js
vue实现列表垂直无缝滚动
Apr 08 Vue.js
vue+elementUI实现表格列的显示与隐藏
Apr 13 Vue.js
vue如何清除浏览器历史栈
May 25 Vue.js
详解Vue 的异常处理机制
Nov 30 #Vue.js
ESLint 是如何检查 .vue 文件的
Nov 30 #Vue.js
Vue用mixin合并重复代码的实现
Nov 27 #Vue.js
使用vue编写h5公众号跳转小程序的实现代码
Nov 27 #Vue.js
在Vue中使用CSS3实现内容无缝滚动的示例代码
Nov 27 #Vue.js
vuex的数据渲染与修改浅析
Nov 26 #Vue.js
vue动态合并单元格并添加小计合计功能示例
Nov 26 #Vue.js
You might like
在windows平台上构建自己的PHP实现方法(仅适用于php5.2)
2013/07/05 PHP
php中heredoc与nowdoc介绍
2014/12/25 PHP
Yii框架中用response保存cookie,用request读取cookie的原理解析
2019/09/04 PHP
js 第二代身份证号码的验证机制代码
2011/05/12 Javascript
JS远程获取网页源代码实例
2013/09/05 Javascript
jQuery中append()方法用法实例
2015/01/08 Javascript
浅谈JavaScript中null和undefined
2015/07/09 Javascript
jQuery获取当前点击的对象元素(实现代码)
2016/05/19 Javascript
JavaScript中有关一个数组中最大值和最小值及它们的下表的输出的解决办法
2016/07/01 Javascript
在Vue组件化中利用axios处理ajax请求的使用方法
2017/08/25 Javascript
php main 与 iframe 相互通讯类(js+php同域/跨域)
2017/09/14 Javascript
ReactNative之FlatList的具体使用方法
2017/11/29 Javascript
原生js添加一个或多个类名的方法分析
2019/07/30 Javascript
laydate只显示时分 不显示秒的功能实现方法
2019/09/28 Javascript
深入webpack打包原理及loader和plugin的实现
2020/05/06 Javascript
js实现随机圆与矩形功能
2020/10/29 Javascript
[58:12]Ti4第二日主赛事败者组 LGD vs iG 3
2014/07/21 DOTA
Python实现递归遍历文件夹并删除文件
2016/04/18 Python
Python时间获取及转换知识汇总
2017/01/11 Python
利用Python循环(包括while&amp;for)各种打印九九乘法表的实例
2017/11/06 Python
windows环境下tensorflow安装过程详解
2018/03/30 Python
解决安装python库时windows error5 报错的问题
2018/10/21 Python
使用python打印十行杨辉三角过程详解
2019/07/10 Python
Django 静态文件配置过程详解
2019/07/23 Python
Python3读写Excel文件(使用xlrd,xlsxwriter,openpyxl3种方式读写实例与优劣)
2020/02/13 Python
Python reduce函数作用及实例解析
2020/05/08 Python
pip install命令安装扩展库整理
2021/03/02 Python
美国廉价机票预订网站:Cheapfaremart
2018/04/28 全球购物
荷兰电脑专场:Paradigit
2018/05/05 全球购物
基督教卡片、励志礼品、家居装饰等:DaySpring
2018/10/12 全球购物
浙大网新C/C++面试解惑
2015/05/27 面试题
新闻学专业个人求职信写作
2014/02/04 职场文书
哈弗商学院毕业生求职信
2014/02/26 职场文书
我们的节日清明节活动总结
2014/04/30 职场文书
基于Python实现股票收益率分析
2022/04/02 Python
《LOL》“克隆大作战”久违归来 幻灵战队皮肤上线
2022/04/03 其他游戏