SoFunction
Updated on 2025-04-06

Do you know how the magic $set is implemented in Vue?

Preface

In daily development,$setIt is also a very practical API, because the core of Vue2's responsive implementation is to utilize ES5, When we change the array or add new attributes to the object by directly modifying the array subscript, we cannot listen to the data changes, and then we will use it$set, let the modified operations also respond. We need to know why, let’s see how $set is implemented in Vue.

Application scenarios

 let dataArr = ["item1"];
 let dataObject = {
      name: "ccs"
    };

    dataArr[2] = "item2";
     = 22;
// The response failed and the page did not display the updated new data
    this.$set(,2,'item2')
    this.$set(,'age',22)
//The response is successful, the page displays the updated new data

set implementation

Next, let's take a look at the definition of $set in Vue

function set(target: Array<any> | Object, key: any, val: any): any {
  if (
    .NODE_ENV !== "production" &&
    (isUndef(target) || isPrimitive(target))
  ) {
    warn(
      `Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`
    );
  }
  if ((target) && isValidArrayIndex(key)) {
     = (, key);
    (key, 1, val);
    return val;
  }
  if (key in target && !(key in )) {
    target[key] = val;
    return val;
  }
  const ob = (target: any).__ob__;
  if (target._isVue || (ob && )) {
    .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(, key, val);
  ();
  return val;
}

First, determine whether the target of set isundefinedand basic type ifundefinedOr the basic type will report an error,Because users should not set things in undefined and basic types, and then determine whether the target is an array and key is a legal index. The legal index refers to an integer with a value greater than or equal to 0. If both conditions are true, call the splice method to insert or modify the array on the target array. HerespliceNot ordinaryspliceIt is the splice in Wang Wei's poem, the splice rewritten by the vue agent

Array implementation response

$set implements the method of modifying the response of an array by the proxy to modify the response. Next, let's take a look at the specific implementation.

const arrayProto = 
export const arrayMethods = (arrayProto)

const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]
function def(obj, key, val, enumerable) {
    (obj, key, {
        value: val,
        enumerable: !!enumerable,
        writable: true,
        configurable: true
    });
}
(function (method) {
  const original = arrayProto[method]
  def(arrayMethods, method, function mutator (...args) {
    const result = (this, args)
    const ob = this.__ob__
    let inserted
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = (2)
        break
    }
    if (inserted) (inserted)
    ()
    return result
  })
})

Proxy rewrites in vue not justsplice,havepush、pop、shift、unshift、splice、sort、reverseThese seven methods are first executedconst result = (this, args)Execute the original array method and get its value, next judge if it is in the arrayAdd valueThen the newly added value is also responsive.The last stepGet this array_ob_objectright_ob_The dep in the distribution update.

If you want to know the responsiveness of vue, you can check the previous articlesThe interviewer asked you about the responsive principle of Vue2, how do you answer?

Object implementation response

$setThe logic in the middle and lower half is used to process object responses, let's continue to look at it

  if (key in target && !(key in )) {
    target[key] = val;
    return val;
  }
  const ob = (target: any).__ob__;
  if (!ob) {
    target[key] = val;
    return val;
  }
  defineReactive(, key, val);
  ();
  return val;

First, if the attribute is directly returned to the end logic in the target object,Because vue will lose its response only when adding attributes that were not originally in the target object.

For examplelet obj={} ='ccs',

When vue is initialized, all attributes in data will be responsive. If the value is an object or an array, a new one will beObserverThe instance is stored in __ob__,If you want to know the responsiveness of vue, you can check the previous articlesThe interviewer asked you about the responsive principle of Vue2, how do you answer

Get the _ob_ of this object for judgment. If it does not exist, it means it isNot initialized by vuea normal object instead ofResponsive ObjectsOtherwise, it will be manually passeddefineReactiveAdd a get method and a set method to the attributeImplement response, and then call it manuallydepInsidenotify()Release updates.

Summarize

The $set method in vue processes arrays and objects essentially the same, adding a response to the added value and then manually triggering the dispatch update.

The above is the details of how the magic $set is implemented in Vue? For more information about Vue's implementation of $set, please follow my other related articles!