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 相关文章推荐
ESLint 是如何检查 .vue 文件的
Nov 30 Vue.js
vue-router定义元信息meta操作
Dec 07 Vue.js
Vue实现图书管理案例
Jan 20 Vue.js
如何在vue 中使用柱状图 并自修改配置
Jan 21 Vue.js
vue实现轮播图帧率播放
Jan 26 Vue.js
学习 Vue.js 遇到的那些坑
Feb 02 Vue.js
vue 使用饿了么UI仿写teambition的筛选功能
Mar 01 Vue.js
vue3.0中使用element的完整步骤
Mar 04 Vue.js
vue+flask实现视频合成功能(拖拽上传)
Mar 04 Vue.js
vue实现同时设置多个倒计时
May 20 Vue.js
Vue过滤器(filter)实现及应用场景详解
Jun 15 Vue.js
Vue3.0中Ref与Reactive的区别示例详析
Jul 07 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框架的理由
2015/09/26 PHP
Swoole源码中如何查询Websocket的连接问题详解
2020/08/30 PHP
JavaScript中的Location地址对象
2008/01/16 Javascript
JQuery给元素添加/删除节点比如select
2013/04/02 Javascript
JavaScript中用sort()方法对数组元素进行排序的操作
2015/06/09 Javascript
深入浅析AngularJS中的module(模块)
2016/01/04 Javascript
基于jQuery实现点击最后一行实现行自增效果的表格
2016/01/12 Javascript
基于javascript实现tab选项卡切换特效调试笔记
2016/03/30 Javascript
浅谈Javascript数组(推荐)
2016/05/17 Javascript
js实现百度地图定位于地址逆解析,显示自己当前的地理位置
2016/12/08 Javascript
nodejs根据ip数组在百度地图中进行定位
2017/03/06 NodeJs
JS实现简单抖动效果
2017/06/01 Javascript
解决React Native端口号修改的方法
2017/07/28 Javascript
详解基于Angular4+ server render(服务端渲染)开发教程
2017/08/28 Javascript
浅谈JavaScript面向对象--继承
2019/03/20 Javascript
Vue实现固定定位图标滑动隐藏效果
2019/05/30 Javascript
Promise扫盲贴
2019/06/24 Javascript
js实现简单的秒表
2020/01/16 Javascript
python修改字典内key对应值的方法
2015/07/11 Python
Python实现的直接插入排序算法示例
2018/04/29 Python
django利用request id便于定位及给日志加上request_id
2018/08/26 Python
使用Python实现从各个子文件夹中复制指定文件的方法
2018/10/25 Python
linux安装python修改默认python版本方法
2019/03/31 Python
Python进程间通信Queue消息队列用法分析
2019/05/22 Python
python try except返回异常的信息字符串代码实例
2019/08/15 Python
对django layer弹窗组件的使用详解
2019/08/31 Python
Python解析多帧dicom数据详解
2020/01/13 Python
python mysql自增字段AUTO_INCREMENT值的修改方式
2020/05/18 Python
Python 如何在字符串中插入变量
2020/08/01 Python
英国顶尖手表珠宝品牌独家授权经销商:HS Johnson
2020/10/28 全球购物
.net面试题
2015/12/22 面试题
介绍JAVA 中的Collection FrameWork(及如何写自己的数据结构)
2014/10/31 面试题
大学专科生推荐信范文
2013/11/23 职场文书
鲜花方阵解说词
2014/02/13 职场文书
企业总经理任命书
2014/06/05 职场文书
镇班子对照检查材料思想汇报
2014/09/24 职场文书