目录
应用场景
set实现
数组实现响应
对象实现响应
总结
首页 web前端 Vue.js 聊聊Vue中$set是如何实现的?

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

Dec 15, 2022 pm 09:26 PM
vue.js

聊聊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.prototype
export const arrayMethods = Object.create(arrayProto)

const methodsToPatch = [
  &#39;push&#39;,
  &#39;pop&#39;,
  &#39;shift&#39;,
  &#39;unshift&#39;,
  &#39;splice&#39;,
  &#39;sort&#39;,
  &#39;reverse&#39;
]
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 &#39;push&#39;:
      case &#39;unshift&#39;:
        inserted = args
        break
      case &#39;splice&#39;:
        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是如何实现的?的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

深入探讨vite是怎么解析.env文件的 深入探讨vite是怎么解析.env文件的 Jan 24, 2023 am 05:30 AM

使用vue框架开发前端项目时,我们部署的时候都会部署多套环境,往往开发、测试以及线上环境调用的接口域名都是不一样的。如何能做到区分呢?那就是使用环境变量和模式。

图文详解如何在Vue项目中集成Ace代码编辑器 图文详解如何在Vue项目中集成Ace代码编辑器 Apr 24, 2023 am 10:52 AM

Ace 是一个用 JavaScript 编写的可嵌入代码编辑器。它与 Sublime、Vim 和 TextMate 等原生编辑器的功能和性能相匹配。它可以很容易地嵌入到任何网页和 JavaScript 应用程序中。Ace 被维护为Cloud9 IDE的主要编辑器 ,并且是 Mozilla Skywriter (Bespin) 项目的继承者。

vue中组件化和模块化有什么区别 vue中组件化和模块化有什么区别 Dec 15, 2022 pm 12:54 PM

组件化和模块化的区别:模块化是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个每个功能模块的职能一致。组件化是从UI界面的角度进行规划;前端的组件化,方便UI组件的重用。

探讨如何在Vue3中编写单元测试 探讨如何在Vue3中编写单元测试 Apr 25, 2023 pm 07:41 PM

当今前端开发中,Vue.js 已经成为了一个非常流行的框架。随着 Vue.js 的不断发展,单元测试变得越来越重要。今天,我们将探讨如何在 Vue.js 3 中编写单元测试,并提供一些最佳实践和常见的问题及解决方案。

深入聊聊vue3中的reactive() 深入聊聊vue3中的reactive() Jan 06, 2023 pm 09:21 PM

前言:在vue3的开发中,reactive是提供实现响应式数据的方法。日常开发这个是使用频率很高的api。这篇文章笔者就来探索其内部运行机制。

Vue中JSX语法和模板语法的简单对比(优劣势分析) Vue中JSX语法和模板语法的简单对比(优劣势分析) Mar 23, 2023 pm 07:53 PM

在Vue.js中,开发人员可以使用两种不同的语法来创建用户界面:JSX语法和模板语法。这两种语法各有优劣,下面就来探讨一下它们的区别和优劣势。

怎么查询当前vue的版本 怎么查询当前vue的版本 Dec 19, 2022 pm 04:55 PM

查询当前vue版本的两种方法:1、在cmd控制台内,执行“npm list vue”命令查询版本,输出结果就是vue的版本号信息;2、在项目中找到并打开package.json文件,查找“dependencies”项即可看到vue的版本信息。

浅析Vue3动态组件怎么进行异常处理 浅析Vue3动态组件怎么进行异常处理 Dec 02, 2022 pm 09:11 PM

Vue3动态组件怎么进行异常处理?下面本篇文章带大家聊聊Vue3 动态组件异常处理的方法,希望对大家有所帮助!

See all articles