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 相关文章推荐
Vue3配置axios跨域实现过程解析
Nov 25 Vue.js
Vue $attrs &amp; inheritAttr实现button禁用效果案例
Dec 07 Vue.js
基于Vue2实现移动端图片上传、压缩、拖拽排序、拖拽删除功能
Jan 05 Vue.js
vue3.0中友好使用antdv示例详解
Jan 05 Vue.js
浅谈Vue开发人员的7个最好的VSCode扩展
Jan 20 Vue.js
vue集成一个支持图片缩放拖拽的富文本编辑器
Jan 29 Vue.js
vue常用高阶函数及综合实例
Feb 25 Vue.js
Vue3 Composition API的使用简介
Mar 29 Vue.js
如何使用vue3打造一个物料库
May 08 Vue.js
vue ref如何获取子组件属性值
Mar 31 Vue.js
vue 给数组添加新对象并赋值
Apr 20 Vue.js
Vue 打包后相对路径的引用问题
Jun 05 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 SQL防注入代码集合
2008/04/25 PHP
用php过滤危险html代码的函数
2008/07/22 PHP
php入门学习知识点三 PHP上传
2011/07/14 PHP
php 记录进行累加并显示总时长为秒的结果
2011/11/04 PHP
PHP判断图片格式的七种方法小结
2013/06/03 PHP
typecho插件编写教程(六):调用接口
2015/05/28 PHP
php_pdo 预处理语句详解
2016/11/21 PHP
详解php用static方法的原因
2018/09/12 PHP
Yii2框架自定义验证规则操作示例
2019/02/08 PHP
node.js中的buffer.slice方法使用说明
2014/12/10 Javascript
JavaScript中的getMilliseconds()方法使用详解
2015/06/10 Javascript
js实现select下拉框菜单
2015/12/08 Javascript
AngularJS  ng-table插件设置排序
2016/09/21 Javascript
Angularjs 设置全局变量的方法总结
2016/10/20 Javascript
进阶之初探nodeJS
2017/01/24 NodeJs
vue router下的html5 history在iis服务器上的设置方法
2017/10/18 Javascript
vue使用xe-utils函数库的具体方法
2018/03/06 Javascript
Vue.js 踩坑记之双向绑定
2018/05/03 Javascript
bootstrap模态框关闭后清除模态框的数据方法
2018/08/10 Javascript
Vue加载组件、动态加载组件的几种方式
2018/08/31 Javascript
微信小程序实现通过js操作wxml的wxss属性示例
2018/12/06 Javascript
JS实现基本的网页计算器功能示例
2020/01/16 Javascript
python实现zencart产品数据导入到magento(python导入数据)
2014/04/03 Python
python数据预处理之将类别数据转换为数值的方法
2017/07/05 Python
python3写爬取B站视频弹幕功能
2017/12/22 Python
python print 按逗号或空格分隔的方法
2018/05/02 Python
Python使用Selenium模块模拟浏览器抓取斗鱼直播间信息示例
2018/07/18 Python
使用pandas实现csv/excel sheet互相转换的方法
2018/12/10 Python
Python图像滤波处理操作示例【基于ImageFilter类】
2019/01/03 Python
django有外键关系的两张表如何相互查找
2020/02/10 Python
使用Python项目生成所有依赖包的清单方式
2020/07/13 Python
python如何实现word批量转HTML
2020/09/30 Python
纯css3实现走马灯效果
2014/12/26 HTML / CSS
荷兰DOD药房中文官网:DeOnlineDrogist
2020/12/27 全球购物
2015年妇委会工作总结
2015/05/22 职场文书
详解Vue slot插槽
2021/11/20 Vue.js