Inhaltsverzeichnis
Stellen Sie eine Frage
Quellcode-Analyse
总结
Heim Web-Frontend View.js Lassen Sie uns über das Zeigeproblem in vue2.x sprechen. Warum zeigt es auf die Vue-Instanz?

Lassen Sie uns über das Zeigeproblem in vue2.x sprechen. Warum zeigt es auf die Vue-Instanz?

Jan 20, 2022 am 10:23 AM
this

In diesem Artikel geht es um das Zeigeproblem in vue2.x und es wird erläutert, warum dies auf die vue-Instanz verweist. Ich hoffe, dass es für alle hilfreich ist!

Lassen Sie uns über das Zeigeproblem in vue2.x sprechen. Warum zeigt es auf die Vue-Instanz?

In der exemplarischen Vorgehensweise zum Gruppencode habe ich versehentlich erwähnt, warum dies direkt auf die Werte in Daten, Methoden, Requisiten und Berechnungen angewendet werden kann. Dann hatte jeder einige Vermutungen, aber es gab keine klare Antwort Schauen Sie sich dieses Problem an. Nachdem ich den Quellcode von Vue verstanden habe, werde ich einen Artikel schreiben, um ihn aufzuzeichnen.

Stellen Sie eine Frage

Normalerweise wird Vue-Code entwickelt und fast immer so geschrieben

export default {
    data() {
        return {
            name: '彭鱼宴'
        }
    },
    methods: {
        greet() {
            console.log(`hello, 我是${this.name}`)
        }
    }
}
Nach dem Login kopieren

Warum kann this.name hier direkt auf den in Daten definierten Namen zugreifen, oder this.someFn kann direkt auf Methoden zugreifen Wie bei der definierten Funktion Mit dieser Frage im Hinterkopf begann ich, den Quellcode von vue2.x zu durchsuchen, um die Antwort zu finden.

Quellcode-Analyse

Hier ist die Quellcodeadresse von Vuevue-Quellcode. Werfen wir zunächst einen Blick auf den Konstruktor der Vue-Instanz. Der Konstruktor befindet sich im Quellcodeverzeichnis /vue/src/core/instance/index.js. Es gibt nicht viel Code für einen Blick Der Konstruktor ist sehr einfach: if (!(diese Instanz von Vue)){} Bestimmen Sie, ob das Schlüsselwort new zum Aufrufen des Konstruktors verwendet wird. Andernfalls wird eine Warnung ausgegeben . Hier ist dies</code >Bezieht sich auf eine Instanz von Vue. Wenn das Schlüsselwort <code>new normal verwendet wird, verwenden Sie einfach die Funktion _init. Ist das nicht sehr einfach?

if (!(this instanceof Vue)){} 判断是不是用了 new 关键词调用构造函数,没有则抛出warning,这里的this指的是Vue的一个实例。如果正常使用了new关键词,就走_init函数,是不是很简单。

_init函数分析

function Vue (options) {
  if (process.env.NODE_ENV !== &#39;production&#39; &&
    !(this instanceof Vue)
  ) {
    warn(&#39;Vue is a constructor and should be called with the `new` keyword&#39;)
  }
  this._init(options)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

export default Vue
Nach dem Login kopieren

_init函数有点长,做了很多事情,这里就不一一解读,和我们此次探索相关的内容应该在initState(vm)这个函数中,我们继续到initState这个函数里看看。

initState函数分析

let uid = 0

export function initMixin (Vue: Class<Component>) {
  Vue.prototype._init = function (options?: Object) {
    const vm: Component = this
    // a uid
    vm._uid = uid++

    let startTag, endTag
    /* istanbul ignore if */
    if (process.env.NODE_ENV !== &#39;production&#39; && config.performance && mark) {
      startTag = `vue-perf-start:${vm._uid}`
      endTag = `vue-perf-end:${vm._uid}`
      mark(startTag)
    }

    // a flag to avoid this being observed
    vm._isVue = true
    // merge options
    if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options)
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }
    /* istanbul ignore else */
    if (process.env.NODE_ENV !== &#39;production&#39;) {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    // expose real self
    vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, &#39;beforeCreate&#39;)
    initInjections(vm) // resolve injections before data/props
    initState(vm)
    initProvide(vm) // resolve provide after data/props
    callHook(vm, &#39;created&#39;)

    /* istanbul ignore if */
    if (process.env.NODE_ENV !== &#39;production&#39; && config.performance && mark) {
      vm._name = formatComponentName(vm, false)
      mark(endTag)
      measure(`vue ${vm._name} init`, startTag, endTag)
    }

    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }
}
Nach dem Login kopieren

可以看出initState做了5件事情

  • 初始化props
  • 初始化methods
  • 初始化data
  • 初始化computed
  • 初始化watch

我们先重点看看初始化methods做了什么

initMethods 初始化方法

export function initState (vm: Component) {
  vm._watchers = []
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props)
  if (opts.methods) initMethods(vm, opts.methods)
  if (opts.data) {
    initData(vm)
  } else {
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}
Nach dem Login kopieren

initMethods主要是一些判断:

function initMethods (vm, methods) {
    var props = vm.$options.props;
    for (var key in methods) {
      {
        if (typeof methods[key] !== &#39;function&#39;) {
          warn(
            "Method \"" + key + "\" has type \"" + (typeof methods[key]) + "\" in the component definition. " +
            "Did you reference the function correctly?",
            vm
          );
        }
        if (props && hasOwn(props, key)) {
          warn(
            ("Method \"" + key + "\" has already been defined as a prop."),
            vm
          );
        }
        if ((key in vm) && isReserved(key)) {
          warn(
            "Method \"" + key + "\" conflicts with an existing Vue instance method. " +
            "Avoid defining component methods that start with _ or $."
          );
        }
      }
      vm[key] = typeof methods[key] !== &#39;function&#39; ? noop : bind(methods[key], vm);
    }
}
Nach dem Login kopieren

除去上述说的这些判断,最重要的就是在vue实例上定义了一遍methods里所有的方法,并且使用bind函数将函数的this指向Vue实例上,就是我们new Vue()的实例对象上。

这就解释了为啥this可以直接访问到methods里的方法。

initData 初始化数据

判断methods中定义的函数是不是函数,不是函数就抛warning;
判断methods中定义的函数名是否与props冲突,冲突抛warning;
判断methods中定义的函数名是否与已经定义在Vue实例上的函数相冲突,冲突的话就建议开发者用_或者$开头命名;
Nach dem Login kopieren

initdata做了哪些事情呢:

  • 先在实例 _data 上赋值,getData函数处理 data 这个 function,返回的是一个对象
  • 判断最终获取到的 data, 不是对象给出警告。
  • 判断methods里的函数和data里的key是否有冲突
  • 判断props和data里的key是否有冲突
  • 判断是不是内部私有的保留属性,若不是就做一层代理,代理到 _data 上
  • 最后监听data,使之成为响应式数据

再看下proxy函数做了什么:

function initData (vm) {
    var data = vm.$options.data;
    data = vm._data = typeof data === &#39;function&#39;
      ? getData(data, vm)
      : data || {};
    if (!isPlainObject(data)) {
      data = {};
      warn(
        &#39;data functions should return an object:\n&#39; +
        &#39;https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function&#39;,
        vm
      );
    }
    // proxy data on instance
    var keys = Object.keys(data);
    var props = vm.$options.props;
    var methods = vm.$options.methods;
    var i = keys.length;
    while (i--) {
      var key = keys[i];
      {
        if (methods && hasOwn(methods, key)) {
          warn(
            ("Method \"" + key + "\" has already been defined as a data property."),
            vm
          );
        }
      }
      if (props && hasOwn(props, key)) {
        warn(
          "The data property \"" + key + "\" is already declared as a prop. " +
          "Use prop default value instead.",
          vm
        );
      } else if (!isReserved(key)) {
        proxy(vm, "_data", key);
      }
    }
    // observe data
    observe(data, true /* asRootData */);
}
Nach dem Login kopieren

其实这里的Object.defineProperty就是用来定义对象的

proxy的用处就是使this.name指向this._data.name

剩下的observe函数不在此次探讨范围,感兴趣的朋友可以自己去看看源码。

总结

回到一开始抛出的问题做一个解答:

  • methods里的方法通过 bind 指定了this为 new Vue的实例(vm),methods里的函数也都定义在vm上了,所以可以直接通过this直接访问到methods里面的函数。

  • data函数返回的数据对象也都存储在了new Vue的实例(vm)上的_data上了,访问 this.name时实际访问的是Object.defineProperty代理后的 this._data.name_init-Funktionsanalyse

  • function noop (a, b, c) {}
    var sharedPropertyDefinition = {
        enumerable: true,
        configurable: true,
        get: noop,
        set: noop
    };
    
    function proxy (target, sourceKey, key) {
        sharedPropertyDefinition.get = function proxyGetter () {
          return this[sourceKey][key]
        };
        sharedPropertyDefinition.set = function proxySetter (val) {
          this[sourceKey][key] = val;
        };
        Object.defineProperty(target, key, sharedPropertyDefinition);
    }
    Nach dem Login kopieren
    Die _init-Funktion ist etwas lang und erledigt viele Dinge, die ich nicht einzeln erklären werde Diesmal bezieht es sich auf unsere Erkundung. Der Inhalt sollte sich in der Funktion initState(vm) befinden.

    initState-Funktionsanalyserrreee

    Es ist ersichtlich, dass initState 5 Dinge tut🎜
    • Requisiten initialisieren🎜
    • Initialisierung Methoden🎜
    • Daten initialisieren. 🎜Außer Für die oben genannten Urteile 🎜das Wichtigste ist, alle Methoden in der Vue-Instanz zu definieren und die Bind-Funktion zu verwenden, um die Funktion auf die Vue-Instanz zu verweisen🎜, die das Instanzobjekt unseres neuen Vue() ist. . 🎜🎜Dies erklärt, warum dadurch direkt auf die Methoden in Methoden zugegriffen werden kann. 🎜🎜🎜initData initialisiert Daten🎜🎜rrreee🎜Was macht initdata: 🎜
      • Zuerst der Instanz _data einen Wert zuweisen, die Funktion getData verarbeitet die Datenfunktion und gibt ein Objekt zurück🎜
      • Urteil endgültig Die erhaltenen Daten sind kein Objekt und es wird eine Warnung ausgegeben. 🎜
      • Bestimmen Sie, ob die Funktion in Methoden mit dem Schlüssel in Daten in Konflikt steht🎜
      • Bestimmen Sie, ob ein Konflikt zwischen Requisiten und dem Schlüssel in Daten besteht🎜
      • Bestimmen Sie, ob es sich um ein internes privates reserviertes Attribut handelt. Wenn nicht, Erstellen Sie eine Ebene Proxy, Proxy für _Daten🎜
      • Endlich auf Daten hören und sie zu reaktionsfähigen Daten machen🎜🎜🎜Schauen wir uns an, was die Proxy-Funktion macht:🎜rrreee🎜Tatsächlich die Object.defineProperty Hier ist der Zweck von
        🎜🎜proxy, der zum Definieren von Objekten verwendet wird, darin, this.name auf this._data.name verweisen zu lassen 🎜🎜der Rest Die Beobachtungsfunktion ist nicht Gegenstand dieser Diskussion. Interessierte Freunde können sich den Quellcode selbst ansehen. 🎜🎜🎜Zusammenfassung🎜🎜🎜Gehen Sie zurück zur am Anfang gestellten Frage und geben Sie eine Antwort: 🎜
        • Die Methode in 🎜methods code> Durch <code>bind wird this als Instanz von new Vue (vm) angegeben, und die Funktionen in Methoden werden auch in vm, sodass Sie über this direkt auf die Funktionen in methods zugreifen können. 🎜🎜
        • 🎜Die von der Funktion data zurückgegebenen Datenobjekte werden auch in _data auf der neuen Vue-Instanz (vm) gespeichert Beim Zugriff auf this.name wird tatsächlich auf this._data.name nach dem Object.defineProperty-Proxy zugegriffen. 🎜🎜🎜🎜Was die Vor- und Nachteile dieses Datenentwurfsmusters betrifft, können Sie weiter erforschen, schließlich ist es nicht Teil dieser Diskussion. 🎜🎜【Verwandte Empfehlung: 🎜vue.js Video-Tutorial🎜】🎜

    Das obige ist der detaillierte Inhalt vonLassen Sie uns über das Zeigeproblem in vue2.x sprechen. Warum zeigt es auf die Vue-Instanz?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Wie man alles in Myrise freischaltet
1 Monate vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Ein Artikel, der diesen Punkt versteht und 70 % der Front-End-Leute erreicht Ein Artikel, der diesen Punkt versteht und 70 % der Front-End-Leute erreicht Sep 06, 2022 pm 05:03 PM

Ein Kollege blieb aufgrund eines Fehlers stecken, auf den dadurch hingewiesen wurde. Dieses Zeigeproblem führte dazu, dass eine Pfeilfunktion verwendet wurde, was dazu führte, dass die entsprechenden Requisiten nicht abgerufen werden konnten. Er wusste es nicht, als ich es ihm vorstellte, und dann habe ich mir bewusst die Front-End-Kommunikationsgruppe angesehen. Bisher verstehen es mindestens 70 % der Front-End-Programmierer nicht Sie diesen Link Wenn alles unklar ist Wenn Sie es noch nicht gelernt haben, geben Sie mir bitte eine große Klappe.

Lassen Sie uns darüber sprechen, warum Vue2 dadurch in verschiedenen Optionen auf Eigenschaften zugreifen kann Lassen Sie uns darüber sprechen, warum Vue2 dadurch in verschiedenen Optionen auf Eigenschaften zugreifen kann Dec 08, 2022 pm 08:22 PM

Dieser Artikel hilft Ihnen bei der Interpretation des Vue-Quellcodes und stellt vor, warum Sie damit in Vue2 auf Eigenschaften in verschiedenen Optionen zugreifen können. Ich hoffe, dass er für alle hilfreich ist!

Clevere Möglichkeit, dieses Schlüsselwort in jQuery zu verwenden Clevere Möglichkeit, dieses Schlüsselwort in jQuery zu verwenden Feb 25, 2024 pm 04:09 PM

Flexible Verwendung dieses Schlüsselworts in jQuery In jQuery ist das Schlüsselwort this ein sehr wichtiges und flexibles Konzept. Es wird verwendet, um auf das aktuell manipulierte DOM-Element zu verweisen. Durch die rationale Verwendung dieses Schlüsselworts können wir Elemente auf der Seite einfach bedienen und verschiedene interaktive Effekte und Funktionen erzielen. In diesem Artikel werden spezifische Codebeispiele kombiniert, um die flexible Verwendung dieses Schlüsselworts in jQuery vorzustellen. Dieses einfache Beispiel Schauen wir uns zunächst ein einfaches Beispiel an. Angenommen, wir haben eine

So verwenden Sie diese Methode in Java So verwenden Sie diese Methode in Java Apr 18, 2023 pm 01:58 PM

1. Schlüsselwort this 1. Typ davon: Welches Objekt aufgerufen wird, ist der Referenztyp dieses Objekts 2. Zusammenfassung der Verwendung 1. this.data;//Zugriffsattribut 2. this.func();//Zugriffsmethode 3.this ( );//Andere Konstruktoren in dieser Klasse aufrufen 3. Erklärung der Verwendung 1.this.data wird in Mitgliedsmethoden verwendet. Lassen Sie uns sehen, was passiert, wenn dies nicht hinzugefügt wird classMyDate{publicintyear;publicintmonth;publicintday; intmonth,intday){ye

Was ist das? Eine ausführliche Analyse dazu in JavaScript Was ist das? Eine ausführliche Analyse dazu in JavaScript Aug 04, 2022 pm 05:02 PM

Was ist das? Der folgende Artikel wird Ihnen dies in JavaScript vorstellen und auf die Unterschiede zwischen verschiedenen Aufrufmethoden von Funktionen eingehen. Ich hoffe, er wird Ihnen hilfreich sein!

Detaillierte Erklärung hierzu in der JavaScript-Pfeilfunktion Detaillierte Erklärung hierzu in der JavaScript-Pfeilfunktion Jan 25, 2024 pm 01:41 PM

Die Pfeilfunktion in JavaScript ist eine relativ neue Syntax. Im Gegenteil, die Pfeilfunktion zeigt auf das Gültigkeitsbereichsobjekt, das sie enthält statisch; 2. Pfeilfunktionen können nicht als Konstruktoren verwendet werden; 3. Pfeilfunktionen können nicht als Methoden verwendet werden.

Methoden zum Initialisieren dieser Referenz und Objektkonstruktion in Java Methoden zum Initialisieren dieser Referenz und Objektkonstruktion in Java May 14, 2023 pm 06:40 PM

1.Diese Referenz 1.1 Warum sollten wir diese Referenz haben? Schreiben wir zunächst ein Beispiel für eine Datumsklasse: publicclassclassCode{publicintyear;publicintmonth;publicintday;publicvoidsetDay(inty,intm,intd){year=y;month=m;day= d;}publicvoidprintDate (){System.out.println(year+"-"+month+"-"+day);}publicstatic

Wie ändert JavaScript diesen Zeiger? Kurze Analyse von drei Methoden Wie ändert JavaScript diesen Zeiger? Kurze Analyse von drei Methoden Sep 19, 2022 am 09:57 AM

Wie ändert JavaScript diesen Zeiger? Der folgende Artikel stellt Ihnen drei Möglichkeiten vor, dies in JS zu ändern. Ich hoffe, er wird Ihnen hilfreich sein!

See all articles