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 相关文章推荐
Vue实现图书管理小案例
Dec 03 Vue.js
vue+element_ui上传文件,并传递额外参数操作
Dec 05 Vue.js
在vue中动态修改css其中一个属性值操作
Dec 07 Vue.js
vue+elementUI动态增加表单项并添加验证的代码详解
Dec 17 Vue.js
基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析
Dec 30 Vue.js
vue3.0中友好使用antdv示例详解
Jan 05 Vue.js
Vue中引入svg图标的两种方式
Jan 14 Vue.js
Vue实现跑马灯样式文字横向滚动
Nov 23 Vue.js
vue代码分块和懒加载非必要资源文件
Apr 11 Vue.js
vue2的 router在使用过程中遇到的一些问题
Apr 13 Vue.js
Vue3实现简易音乐播放器组件
Aug 14 Vue.js
Vue router配置与使用分析讲解
Dec 24 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
PHP中for与foreach的区别分析
2011/03/09 PHP
php获取mysql数据库中的所有表名的代码
2011/04/23 PHP
php将gd生成的图片缓存到memcache的小例子
2013/06/05 PHP
php读取mysql的简单实例
2014/01/15 PHP
php实现断点续传大文件示例代码
2020/06/19 PHP
js之WEB开发调试利器:Firebug 下载
2007/01/13 Javascript
从sohu弄下来的flash中展示图片的代码
2007/04/27 Javascript
Mootools 1.2教程(3) 数组使用简介
2009/09/14 Javascript
HTML Dom与Css控制方法
2010/10/25 Javascript
一个基于jquery的文本框记数器
2012/09/19 Javascript
php实例分享之实现显示网站运行时间
2014/05/20 Javascript
js实现ArrayList功能附实例代码
2014/10/29 Javascript
使用jQuery不判断浏览器高度解决iframe自适应高度问题
2014/12/16 Javascript
JS onkeypress兼容性写法详解
2016/04/27 Javascript
JavaScript自学笔记(必看篇)
2016/06/23 Javascript
Javascript中的对象和原型(二)
2016/08/12 Javascript
详解在WebStorm中添加Vue.js单文件组件的高亮及语法支持
2017/10/21 Javascript
基于node搭建服务器,写接口,调接口,跨域的实例
2018/05/13 Javascript
element-ui中的select下拉列表设置默认值方法
2018/08/24 Javascript
详解webpack-dev-server使用方法
2018/09/14 Javascript
bootstrap tooltips在 angularJS中的使用方法
2019/04/10 Javascript
关于vue项目中搜索节流的实现代码
2019/09/17 Javascript
解决Vue 给mapState中定义的属性赋值报错的问题
2020/06/22 Javascript
[34:39]Secret vs VG 2018国际邀请赛淘汰赛BO3 第二场 8.23
2018/08/24 DOTA
Python列表计数及插入实例
2014/12/17 Python
详解Python list 与 NumPy.ndarry 切片之间的对比
2017/07/24 Python
Flask 让jsonify返回的json串支持中文显示的方法
2018/03/26 Python
python opencv人脸检测提取及保存方法
2018/08/03 Python
使用50行Python代码从零开始实现一个AI平衡小游戏
2018/11/21 Python
python实现数字炸弹游戏
2020/07/17 Python
瑞典首都斯德哥尔摩的多元奢侈时尚品牌:Acne Studios
2017/07/09 全球购物
网友共享的几个面试题关于Java和Unix等方面的
2016/09/08 面试题
市场营销专业推荐信
2013/11/03 职场文书
大学军训感言200字
2014/02/26 职场文书
羽毛球比赛策划方案
2014/06/13 职场文书
用Python将库打包发布到pypi
2021/04/13 Python