>웹 프론트엔드 >View.js >Vue에서 $set가 어떻게 구현되는지 이야기해 볼까요?

Vue에서 $set가 어떻게 구현되는지 이야기해 볼까요?

青灯夜游
青灯夜游앞으로
2022-12-15 21:26:323068검색

Vue에서 $set가 어떻게 구현되는지 이야기해 볼까요?

일상 개발에서 $set는 매우 실용적인 API이기도 합니다. 왜냐하면 Vue2 응답성의 핵심은 ES5의 Object.defineProperty를 사용하는 것이기 때문입니다. 배열 첨자를 직접 수정하여 개체에 새 속성을 추가하거나 Object.defineproperty는 데이터 변경 사항을 모니터링할 수 없습니다. 이때 모든 사람은 $set를 사용하므로 수정된 작업도 응답을 구현합니다. 우리는 그것을 알고 있지만 그 이유도 알고 있습니다. 다음으로 Vue에서 $set가 어떻게 구현되는지 살펴보겠습니다. [관련 권장사항: vuejs 비디오 튜토리얼$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()]

애플리케이션 시나리오

rrreee

set 구현

다음으로 Vue에서 $set의 정의를 살펴보겠습니다

rrreee

소스 코드에서 먼저 set의 대상이 인지 확인합니다. 정의되지 않음기본 유형 정의되지 않음 또는 기본 유형인 경우 오류가 보고됩니다.
사용자는 정의되지 않은 기본 유형을 설정해서는 안 되기 때문입니다.,
그러면 대상이 배열인지, 키가 합법적인 색인인지 판단됩니다. 합법적인 색인은 값을 갖는 정수를 참조합니다. 0보다 크거나 같습니다.
두 조건이 모두 true인 경우 배열을 삽입하거나 수정하려면 대상 배열에서 splice 메소드를 호출하고
splice code> 여기서는 일반적인 스플라이스가 아닙니다. Wang Wei의 시에서 스플라이스는 스플라이스입니다. vue 프록시에 의해 다시 작성된 Strong>

배열 구현 응답

$set가 응답을 수정하기 위해 배열을 구현하는 방식은 배열의 일부입니다. 다음으로 구체적인 구현을 살펴보겠습니다rrreee

vue. 프록시는 splice 이상의 기능을 다시 작성하며, push, pop, Shift의 7가지 메서드가 있습니다. , 이동 해제, 결합, 정렬, 역방향. 먼저 const result = original.apply(this, args)원래 배열의 메서드를 실행하고 해당 값을 가져온 다음 배열에 추가되었는지 확인합니다. Strong> 값을 추가하면 새로 추가된 값에 대한 응답성이 실현됩니다.
마지막 단계는 이 배열의 _ob_ 개체를 가져옵니다. .code><code>_ob_에 dep를 배포하고 업데이트합니다.
Vue의 반응성에 대해 더 자세히 알고 싶다면 이전 기사를 확인하세요.
면접관이 Vue2의 반응성 원칙에 대해 질문했습니다. 어떻게 대답하셨나요? - Nuggets (juejin.cn) 🎜🎜

객체 구현 응답 🎜🎜$set 하단의 로직은 객체 처리에 사용됩니다. , 계속해서 살펴보겠습니다.🎜rrreee🎜먼저 속성이 대상 객체에 직접 반환되는지 판단하여 로직을 종료합니다.
Vue는 원래 존재하지 않는 속성만 추가하기 때문입니다. 응답 손실,
예를 들어 obj={} obj.name='ccs',
vue는 다음의 모든 속성을 변경합니다. 초기화 중 데이터가 응답하게 됩니다. 값이 객체 또는 배열인 경우 새 Observer 인스턴스가 __ob__에 저장됩니다. vue의 응답성에 대해 자세히 알아보려면 이전 항목을 확인하세요. 기사
면접관님이 Vue2에 대해 질문하셨습니다. 응답성의 원칙에 대해 어떻게 대답하시나요? - Nuggets (juejin.cn)🎜
판단을 위해 이 객체의 _ob_을 가져옵니다. 존재하지 않으면 vue에서 초기화되지 않은 일반 객체이며 응답이 아니라는 의미입니다. /strong> 그렇지 않으면 응답을 구현하기 위해 defineReactive를 통해 속성에 get 메서드와 set 메서드를 수동으로 추가하고,
수동으로 dep <code>notify()는 업데이트를 게시합니다. 🎜🎜요약🎜🎜vue의 $set 메소드는 배열과 객체를 기본적으로 동일한 방식으로 처리하며 새 값에 응답을 추가한 다음 수동으로 디스패치 업데이트를 트리거합니다. 🎜🎜 (학습 영상 공유: 🎜vuejs 입문 튜토리얼🎜, 🎜기본 프로그래밍 영상🎜)🎜

위 내용은 Vue에서 $set가 어떻게 구현되는지 이야기해 볼까요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제