目次
質問を投げる
ソース コード解析
ホームページ ウェブフロントエンド Vue.js vue2.x でのこのポインティングの問題について話しましょう。なぜ vue インスタンスを指すのでしょうか?

vue2.x でのこのポインティングの問題について話しましょう。なぜ vue インスタンスを指すのでしょうか?

Jan 20, 2022 am 10:23 AM
this

この記事では、vue2.x における this のポインティングの問題について説明し、これが vue インスタンスを指す理由を紹介します。

vue2.x でのこのポインティングの問題について話しましょう。なぜ vue インスタンスを指すのでしょうか?

グループ内のコード ウォークスルーで、これがデータ、メソッド、プロパティ、および計算の値に直接呼び出せる理由について偶然言及しました。その後、誰もがいくつかの推測をしました。この疑問を解決するためにvueのソースコードを確認して、ある程度理解できたので記録として記事を書きました。

質問を投げる

通常、vue コードを開発する場合、ほとんどの場合次のように記述します

export default {
    data() {
        return {
            name: '彭鱼宴'
        }
    },
    methods: {
        greet() {
            console.log(`hello, 我是${this.name}`)
        }
    }
}
ログイン後にコピー

なぜここの this.name がデータに直接アクセスできるのでしょうか?で定義された名前について、または this.someFn はメソッドで定義された関数に直接アクセスできますか? この疑問をきっかけに、私は答えを見つけるために vue2.x のソース コードを調べ始めました。

ソース コード解析

vuevue ソース コード のソース コード アドレスは次のとおりです。まず、vue インスタンスのコンストラクターを見てみましょう。コンストラクターは、ソース コード ディレクトリ/vue/src/core/instance/index.js にあります。コードはそれほど多くありません。すべて投稿して確認してください。

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

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

export default Vue
ログイン後にコピー

コンストラクタは非常にシンプルです。if (!(thisinstanceof Vue)){} new キーワードを使用してコンストラクタを呼び出すかどうかを判断します。使用しない場合は、警告が表示されます。ここに this がスローされます。これは Vue のインスタンスを指します。普通に new キーワードを使うのであれば、_init 関数を使うだけです。とても簡単ではないでしょうか。

_init 関数の分析

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)
    }
  }
}
ログイン後にコピー

_init 関数は少し長く、多くのことを行うため、説明は省略します。関連する内容は initState(vm) 関数内にあるはずです。initState 関数に進みましょう。

initState 関数の分析

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)
  }
}
ログイン後にコピー

initState が 5 つのことを行っていることがわかります

  • プロパティの初期化
  • 初期化メソッド
  • 初期化データ
  • 計算された初期化
  • 初期化ウォッチ

最初に、初期化メソッドの機能に焦点を当てましょう

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);
    }
}
ログイン後にコピー

initMethods は主にいくつかの判断で構成されます:

判断methods中定义的函数是不是函数,不是函数就抛warning;
判断methods中定义的函数名是否与props冲突,冲突抛warning;
判断methods中定义的函数名是否与已经定义在Vue实例上的函数相冲突,冲突的话就建议开发者用_或者$开头命名;
ログイン後にコピー

上記の判断を除き、最も重要なことはvue メソッド内のすべてのメソッドはインスタンス上で定義され、バインド関数を使用して関数の this を新しい Vue() のインスタンス オブジェクトである Vue インスタンス にポイントします。

これは、メソッド内のメソッドに直接アクセスできる理由を説明しています。

initData はデータを初期化します

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 */);
}
ログイン後にコピー

initdata は何をしますか:

  • まず、instance_data に値を割り当て、getData 関数がそのデータを処理します。 data この関数は警告を与えるためのオブジェクトではなく、最終的に得られたデータを判定するためのオブジェクト
  • を返します。
  • メソッド内の関数がデータ内のキーと競合するかどうかを判断します。
  • props とデータ内のキーとの間に競合があるかどうかを判断します。
  • それが内部プライベートであるかどうかを判断します。そうでない場合は、プロキシのレイヤーを作成して _data にプロキシします
  • 最後にデータをリッスンして応答性の高いデータにします

プロキシの機能を見てみましょうdos:

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);
}
ログイン後にコピー

実際、ここの Object.defineProperty はオブジェクトを定義するために使用されます。

proxy の目的は次のとおりです。 this.name## を使用するには #this._data.name

をポイントします。残りの観察関数はこのディスカッションの範囲外です。興味のある友人はソースをチェックしてください。自分自身をコード化します。

概要

最初に挙げた質問に戻って、次のように答えます:

  • メソッド bind のメソッドは this を新しい Vue (vm) のインスタンスとして指定しており、メソッド内の関数も vm# で定義されています## がインストールされているため、this を通じて methods の関数に直接アクセスできます。

  • data

    関数によって返されたデータ オブジェクトは、新しい Vue インスタンス (vm) の _data## にも保存されます。 #上で、this.name にアクセスすると、実際にアクセスされるのは、プロキシ this._data.name の後の Object.defineProperty です。

    このデータの設計パターンの長所と短所については、この議論の一部ではないので、引き続き調査してください。
[関連する推奨事項:

vue.js ビデオ チュートリアル

]

以上がvue2.x でのこのポインティングの問題について話しましょう。なぜ vue インスタンスを指すのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

この点を理解してフロントエンド担当者の7割をキャッチアップした記事 この点を理解してフロントエンド担当者の7割をキャッチアップした記事 Sep 06, 2022 pm 05:03 PM

同僚は、これによって指摘されたバグのために立ち往生しました。Vue2 のこの指摘の問題により、アロー関数が使用され、その結果、対応する props を取得できなくなりました。私がそれを彼に紹介したとき、彼はそれを知りませんでした。その後、私はわざとフロントエンド コミュニケーション グループに目を向けました。これまでのところ、フロントエンド プログラマーの少なくとも 70% はまだそれを理解していません。今日私はそれを共有しますyou this link. もしすべてが間違っている場合 まだ学習していない場合は、大きな口を与えてください。

Vue2 がこれを通じてさまざまなオプションのプロパティにアクセスできる理由について話しましょう Vue2 がこれを通じてさまざまなオプションのプロパティにアクセスできる理由について話しましょう Dec 08, 2022 pm 08:22 PM

この記事は、vue ソース コードを解釈するのに役立ち、これを使用して Vue2 のさまざまなオプションのプロパティにアクセスできる理由を紹介します。

jQuery でこのキーワードを使用する賢い方法 jQuery でこのキーワードを使用する賢い方法 Feb 25, 2024 pm 04:09 PM

jQuery での this キーワードの柔軟な使用 jQuery では、this キーワードは非常に重要かつ柔軟な概念であり、現在操作されている DOM 要素を参照するために使用されます。このキーワードを合理的に使用することで、ページ上の要素を簡単に操作し、さまざまなインタラクティブな効果や機能を実現できます。この記事では、特定のコード例を組み合わせて、jQuery でのこのキーワードの柔軟な使用方法を紹介します。簡単なこの例 まず、簡単なこの例を見てみましょう。あるとします。

Java でこのメソッドを使用する方法 Java でこのメソッドを使用する方法 Apr 18, 2023 pm 01:58 PM

1. this キーワード 1. this の型: どのオブジェクトが呼び出されるかがそのオブジェクトの参照型 2. 使用法の概要 1. this.data;//アクセス属性 2. this.func();// アクセスメソッド 3.this ( );//このクラス内の他のコンストラクタを呼び出す 3. 使い方の説明 1.this.dataはメンバメソッドで使用しているので、これを追加しないとどうなるかを見てみましょう classMyDate{publicintyear;publicintmonth;publicintday; publicvoidsetDate(intyear, intmonth,intday){はい

これは何ですか? JavaScript でのこれの詳細な分析 これは何ですか? JavaScript でのこれの詳細な分析 Aug 04, 2022 pm 05:02 PM

これは何ですか?次の記事では、JavaScript でのこれについて説明し、関数の呼び出し方法の違いによる違いについて説明します。

JavaScriptのアロー関数で詳しく解説 JavaScriptのアロー関数で詳しく解説 Jan 25, 2024 pm 01:41 PM

JavaScript のアロー関数は比較的新しい構文です。独自の this キーワードはありません。逆に、アロー関数の this は、それを含むスコープ オブジェクトを指します。影響は次のとおりです: 1. アロー関数の this は次のとおりです。 static; 2. アロー関数はコンストラクタとして使用できません; 3. アロー関数はメソッドとして使用できません。

Java でのこの参照とオブジェクト構築の初期化メソッド Java でのこの参照とオブジェクト構築の初期化メソッド May 14, 2023 pm 06:40 PM

1.this リファレンス 1.1 this リファレンスがあるのはなぜですか? まず、日付クラスの例を書いてみましょう: publicclassclassCode{publicintyear;publicintmonth;publicintday;publicvoidsetDay(inty,intm,intd){year=y;month=m;day= d;}publicvoidprintDate (){System.out.println(年+"-"+月+"-"+日);}publicstatic

JavaScript はこのポインタをどのように変更するのでしょうか? 3 つの方法の簡単な分析 JavaScript はこのポインタをどのように変更するのでしょうか? 3 つの方法の簡単な分析 Sep 19, 2022 am 09:57 AM

JavaScript はこのポインタをどのように変更するのでしょうか?次の記事では、JS でこのポインターを変更する 3 つの方法を紹介します。

See all articles