聊聊Vue中$set是如何实现的?

广告:宝塔Linux面板高效运维的服务器管理软件 点击【 https://www.bt.cn/p/uNLv1L 】立即购买

聊聊Vue中$set是如何实现的?

在日常开发中,$set的也是一个非常实用的API,因为Vue2实现响应式的核心是利用了ES5的Object.defineProperty,当我们通过直接修改数组下标更改数组或者给对象添加新的属性,这个时候Object.defineproperty是监听不到数据的变化的,这时候大家就会用上$set,让修改的操作也实现响应,我们知其然更要知其所以然,接下来看一下Vue中的$set是如何实现的。【相关推荐:vuejs视频教程、web前端开发】

应用场景
 let dataArr = ["item1"]; let dataObject = {      name: "ccs"    };    dataArr[2] = "item2";    dataObject.age = 22;    响应失败,页面没有显示更新新增的数据    this.$set(this.dataArr,2,'item2')    this.$set(this.dataObject,'age',22)    响应成功,页面显示更新新增的数据
登录后复制set实现

接下来我们看一下$set在Vue中的定义

function set(target: Array<any> | Object, key: any, val: any): any {  if (    process.env.NODE_ENV !== "production" &&    (isUndef(target) || isPrimitive(target))  ) {    warn(      `Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`    );  }  if (Array.isArray(target) && isValidArrayIndex(key)) {    target.length = Math.max(target.length, key);    target.splice(key, 1, val);    return val;  }  if (key in target && !(key in Object.prototype)) {    target[key] = val;    return val;  }  const ob = (target: any).__ob__;  if (target._isVue || (ob && ob.vmCount)) {    process.env.NODE_ENV !== "production" &&      warn(        "Avoid adding reactive properties to a Vue instance or its root $data " +          "at runtime - declare it upfront in the data option."      );    return val;  }  if (!ob) {    target[key] = val;    return val;  }  defineReactive(ob.value, key, val);  ob.dep.notify();  return val;}
登录后复制

在源码中首先判断set的目标是否是undefined基本类型如果是undefined基本类型就报错,因为用户不应该往undefined和基本类型中set东西,然后又判断了目标是否是数组与key是不是合法的index,合法的index是指值为大于等于0的整数,如果两个条件都成立就对目标数组调用splice方法插入或者修改数组,这里的splice不是普通的splice是王维诗里的splice,是被vue代理重写过的splice

数组实现响应

$set实现数组修改响应的方式是代理重写的数组的一部分方法,接下来我们看一下具体实现

const arrayProto = Array.prototypeexport const arrayMethods = Object.create(arrayProto)const methodsToPatch = [  'push',  'pop',  'shift',  'unshift',  'splice',  'sort',  'reverse']function def(obj, key, val, enumerable) {    Object.defineProperty(obj, key, {        value: val,        enumerable: !!enumerable,        writable: true,        configurable: true    });}methodsToPatch.forEach(function (method) {  const original = arrayProto[method]  def(arrayMethods, method, function mutator (...args) {    const result = original.apply(this, args)    const ob = this.__ob__    let inserted    switch (method) {      case 'push':      case 'unshift':        inserted = args        break      case 'splice':        inserted = args.slice(2)        break    }    if (inserted) ob.observeArray(inserted)    ob.dep.notify()    return result  })})
登录后复制

vue中代理重写的不只是splice,有push、pop、shift、unshift、splice、sort、reverse这七个方法,首先执行了const result = original.apply(this, args)执行原本数组的方法并获取它的值,接下来判断如果是往数组中添加值就将新添加的值也实现响应式,最后一步拿到这个数组的_ob_对象_ob_里的dep进行派发更新。想深入了解vue的响应式可以查阅往期文章面试官问你Vue2的响应式原理,你怎么答? - 掘金 (juejin.cn)

对象实现响应

$set中下半部分的逻辑就是用来处理对象响应的,我们接着往下看

  if (key in target && !(key in Object.prototype)) {    target[key] = val;    return val;  }  const ob = (target: any).__ob__;  if (!ob) {    target[key] = val;    return val;  }  defineReactive(ob.value, key, val);  ob.dep.notify();  return val;
登录后复制

首先判断了属性如果在目标对象中直接return结束逻辑,因为vue只有添加目标对象中原本没有的属性时才会失去响应例如 let obj={} obj.name='ccs',vue在初始化的时候会将data里的所有属性都变成响应式,如果的值是对象或者数组则会new一个Observer实例储存在__ob__,想深入了解vue的响应式可以查阅往期文章面试官问你Vue2的响应式原理,你怎么答? - 掘金 (juejin.cn)拿到这个对象的_ob_进行判断,如果不存在就说明是未经过vue初始化的普通对象而不是响应式对象否则就手动通过defineReactive为属性添加get方法与set方法实现响应,然后手动调用dep里的notify()发布更新。

总结

vue中$set方法对数组和对象的处理本质上的一样的,对新增的值添加响应然后手动触发派发更新。

(学习视频分享:vuejs入门教程、编程基础视频)

以上就是聊聊Vue中$set是如何实现的?的详细内容,更多请关注9543建站博客其它相关文章!

广告:SSL证书一年128.66元起,点击购买~~~

9543建站博客
一个专注于网站开发、微信开发的技术类纯净博客。
作者头像
admin创始人

肥猫,知名SEO博客站长,14年SEO经验。

上一篇:聊聊uniapp导航栏按钮全局方法
下一篇:nodejs可以做app吗

发表评论

关闭广告
关闭广告