1. 例: これはデータとメソッドを直接取得できます例: 定数vm = 新しいVue({ データ: { 名前: 「私は若川です」 }, メソッド: { 言う名前(){ コンソールにログ出力します。 } }, }); console.log(vm.name); // 私は Ruochuan ですconsole.log(vm.sayName()); // 私は Ruochuan です こうすることで、私が Ruochuan であることを出力できます。好奇心旺盛な人は、なぜこれに直接アクセスできるのか疑問に思うでしょう。 では、なぜ 関数Person(オプション){ } const p = 新しいPerson({ データ: { 名前: '若川' }, メソッド: { 言う名前(){ コンソールにログ出力します。 } } }); コンソールにログ出力します。 // 未定義 コンソールにログ出力します。 // キャッチされない TypeError: p.sayName は関数ではありません あなたなら、どうやってそれを達成しますか?これらの質問を参考に、Vue2 のソースコードをデバッグして学習してみましょう。 2. 環境を準備し、ソースコードをデバッグして詳細を確認します。ローカルに新しいフォルダー <script src="https://unpkg.com/[email protected]/dist/vue.js"></script> <スクリプト> 定数vm = 新しいVue({ データ: { 名前: 「私は若川です」 }, メソッド: { 言う名前(){ コンソールにログ出力します。 } }, }); console.log(仮想マシン名); コンソールにログ出力します。 </スクリプト> 次に、 npm i -g http-server CDの例 http サーバー。 // ポートが使用中の場合は、ポート http-server -p 8081 を指定することもできます。 この方法では、先ほど作成した
ページを更新した後、F11 キーを押して関数に入ります。ブレークポイントは Vue コンストラクターに入ります。 2.1 Vue コンストラクタ関数 Vue (オプション) { if (!(このインスタンス Vue) ){ warn('Vue はコンストラクターなので、`new` キーワードで呼び出す必要があります'); } this._init(オプション); } // 初期化 initMixin(Vue); Vue.js のインスタンスを Vue.js にインポートします。 イベントミックスイン(Vue); ライフサイクルミックスイン(Vue); レンダリングミックスイン(Vue);
jQuery = function(セレクター、コンテキスト) { // 新しいオブジェクトを返します return new jQuery.fn.init( selector, context ); };
2.2 _init初期化関数
// コードは削除されました function initMixin (Vue) { Vue.prototype._init = 関数 (オプション) { var vm = this; // uid vm._uid = uid$3++; // これを回避するためのフラグ vm._isVue = true; // マージオプション if (オプション && options._isComponent) { // 内部コンポーネントのインスタンス化を最適化 // 動的オプションのマージは非常に遅く、 // 内部コンポーネント オプションには特別な処理が必要です。 initInternalComponent(vm、オプション); } それ以外 { vm.$options = mergeOptions( コンストラクタオプションを解決します(vm.constructor)、 オプション || {}, 仮想 ); } // 本当の自分をさらけ出す vm._self を vm に追加します。 ライフサイクルを初期化します(vm); イベントを初期化します(vm); initRender(vm); フックを呼び出します(vm、'beforeCreate')。 initInjections(vm); // データ/プロパティの前にインジェクションを解決する // 初期化状態 initState(vm); initProvide(vm); // data/props の後に provide を解決する callHook(vm, 'created'); }; }
2.3 initState 初期化状態関数名から判断すると、この関数の主な機能は次のとおりです。
関数 initState (vm) { vm._watchers = []; var opts = vm.$options; opts.props の場合、 initProps(vm, opts.props); } // 渡されるメソッド、初期化メソッド if (opts.methods) { initMethods(vm, opts.methods); } // データを入力し、データを初期化する if (opts.data) { initData(vm); } それ以外 { 観察(vm._data = {}, true /* asRootData */); } opts.computed の場合、 initComputed(vm, opts.computed); } opts.watch の場合、opts.watch は nativeWatch と等しくなります。 initWatch(vm, opts.watch); } } まず、初期化
2.4 initMethods 初期化メソッド関数 initMethods (vm, メソッド) { var props = vm.$options.props; for (var key in メソッド) { { if (typeof methods[key] !== 'function') { 警告( "メソッド \"" + key + "\" は、コンポーネント定義で型 \"" + (typeof methods[key]) + "\" を持ちます。" + 「関数を正しく参照しましたか?」 仮想 ); } もしprops && hasOwn(props, key) であれば 警告( (「メソッド \"" + キー + "\" はすでにプロパティとして定義されています。」) 仮想 ); } if ((キーがVM内にある) && isReserved(キー)) { 警告( 「メソッド \"" + キー + "\" は既存の Vue インスタンス メソッドと競合します。" + 「_ または $ で始まるコンポーネント メソッドの定義は避けてください。」 ); } } vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm); } }
これらの判断とは別に、 このため、 this を通じて マウスを 2.4.1 bindは関数を返し、これが指すものを変更します関数 polyfillBind (fn, ctx) { 関数boundFn(a){ var l = 引数の長さ; 戻るl ? l > 1 ? fn.apply(ctx, 引数) : fn.call(ctx, a) : fn.call(ctx) } 境界Fn._length = fn.length; 戻り値boundFn } 関数nativeBind(fn, ctx) { fn.bind(ctx) を返す } var bind = Function.prototype.bind ? ネイティブバインド :ポリフィルバインド; 簡単に言えば、ネイティブ
2.5 initData データの初期化
関数 initData (vm) { var data = vm.$options.data; data = vm._data = typeof data === 'function' ? getData(データ、vm) : データ || {}; if (!isPlainObject(データ)) { データ = {}; 警告( 'データ関数はオブジェクトを返す必要があります:\n' + 'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function', 仮想 ); } // インスタンス上のプロキシデータ var keys = Object.keys(データ); var props = vm.$options.props; var メソッド = vm.$options.methods; var i = キーの長さ; (i--) { var キー = keys[i]; { if (メソッド && hasOwn(メソッド、キー)) { 警告( (「メソッド \"" + キー + "\" はすでにデータ プロパティとして定義されています。」) 仮想 ); } } もしprops && hasOwn(props, key) であれば 警告( 「データ プロパティ \"" + キー + "\" はすでにプロパティとして宣言されています。」 + "代わりにプロパティのデフォルト値を使用してください。", 仮想 ); } そうでなければ (!isReserved(key)) { プロキシ(vm、"_data"、キー); } } // データを観察する 観察(データ、true /* asRootData */); } 2.5.1 データ取得関数の場合は、関数を呼び出して実行し、オブジェクトを取得します。 関数 getData (データ, vm) { // #7573 データゲッターを呼び出すときに依存関係コレクションを無効にする プッシュターゲット(); 試す { データを返します。call(vm, vm) } キャッチ (e) { handleError(e, vm, "データ()"); 戻る {} ついに ポップターゲット(); } } 2.5.2 プロキシ実際、 /** * 何も操作しません。 * 無駄なトランスパイルコードを残さずに Flow を満足させるための引数のスタブ化 * ...rest を使用 (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/)。 */ 関数 noop (a, b, c) {} var 共有プロパティ定義 = { 列挙可能: true、 設定可能: true、 取得: いいえ、 設定: なし }; 関数プロキシ(ターゲット、ソースキー、キー){ sharedPropertyDefinition.get = 関数 proxyGetter() { this[sourceKey][key]を返す }; sharedPropertyDefinition.set = 関数 proxySetter (val) { this[ソースキー][キー] = val; }; Object.defineProperty(ターゲット、キー、共有プロパティ定義); } 2.5.3 Object.definePropertyはオブジェクトのプロパティを定義します
2.6 記事に出てくるいくつかの関数を最終的に統一的に説明する2.6.1 hasOwn オブジェクト自体が所有するプロパティですか?デバッグ モードで、Alt キーを押しながらマウスをメソッド名の上に移動すると、関数が定義されている場所を確認できます。クリックするとジャンプします。 /** * オブジェクトにプロパティがあるかどうかを確認します。 */ var hasOwnProperty = Object.prototype.hasOwnProperty; 関数hasOwn(obj,キー){ hasOwnProperty.call(obj, key) を返します。 } hasOwn({ a: undefined }, 'a') // 真 hasOwn({}, 'a') // 偽 hasOwn({}, 'hasOwnProperty') // 偽 hasOwn({}, 'toString') // 偽 // これはプロパティ自体のプロパティであり、プロトタイプ チェーンを通じて上方向に検索されるものではありません。 2.6.2 isReserved $と_で始まる内部プライベート予約文字列であるかどうか/** * 文字列が $ または _ で始まっているかどうかを確認します */ 関数isReserved(str) { var c = (str + '').charCodeAt(0); c === 0x24 || c === 0x5F を返す } isReserved('_data'); // 真 isReserved('$options'); // 真 isReserved('data'); // 偽 isReserved('options'); // false 3. 最後に、60行以上のコードで簡略化されたバージョンを実装します。関数 noop (a, b, c) {} var 共有プロパティ定義 = { 列挙可能: true、 設定可能: true、 取得: いいえ、 設定: なし }; 関数プロキシ(ターゲット、ソースキー、キー){ sharedPropertyDefinition.get = 関数 proxyGetter() { this[sourceKey][key]を返す }; sharedPropertyDefinition.set = 関数 proxySetter (val) { this[ソースキー][キー] = val; }; Object.defineProperty(ターゲット、キー、共有プロパティ定義); } 関数 initData(vm){ 定数データ = vm._data = vm.$options.data; const keys = Object.keys(データ); var i = キーの長さ; (i--) { var キー = keys[i]; プロキシ(vm、'_data'、キー); } } 関数 initMethods(vm, methods){ for (var key in メソッド) { vm[key] = typeof methods[key] !== 'function' ? noop : methods[key].bind(vm); } } 関数Person(オプション){ vm = this とします。 vm.$options = オプション; var opts = vm.$options; if(opts.data){ initData(vm); } if(opts.methods){ initMethods(vm, opts.methods) } } const p = 新しいPerson({ データ: { 名前: '若川' }, メソッド: { 言う名前(){ コンソールにログ出力します。 } } }); コンソールにログ出力します。 // 実装前: 未定義 // '若川' コンソールにログ出力します。 // 実装前: キャッチされない TypeError: p.sayName は関数ではありません // '若川' 4. 結論この記事で取り上げる基礎知識は主に以下の通りです。
この記事は、ソースコードを読む読者から寄せられた疑問に答えることを目的としています。Vue ソースコードをデバッグして答えを見つける方法について詳しく説明します。 Vue2 this がデータと 以下もご興味があるかもしれません:
|
ブラウザ (Web ドライバー) ベースの Selenium テクノロジを使用してデータをクロールす...
カルーセルを作りたい場合、まずその原理を理解する必要があります。画像を右から左にスライドさせるにはど...
目次フレーム最高レベルのエラー報告活発なコミュニティとチーム冗談モカ推奨プラグインVue テストライ...
目次導入Homebrewをインストールするnvmをインストールするノードをインストールするインストー...
FTP は主にファイル転送に使用され、Linux では vsftpd で実装されるのが一般的です。F...
目次1. 問題2. 解決策オプション1:オプション2: 1. 問題この話は、エラーと脱落率を照会する...
説明するこのインターフェースを呼び出すときは、次の点に注意する必要があります。パブリック IP アド...
序文最良の方法は、あなたが思いつく最も速い方法ではないかもしれません。職場で一時的に使用するスクリプ...
この例では、jQuery を使用してマウス ドラッグ イメージ機能を実装します。まず、ラッパーを設定...
react-routerでは、コンポーネント内のジャンプは<Link>で使用できます。し...
1. Linuxファイアウォールの基礎Linux ファイアウォール システムは主にネットワーク層で動...
MySQL 最大接続数の表示と最大接続数の変更1. 最大接続数を確認する '%max_con...
Mysql Workbench はオープンソースのデータベース クライアントです。このオープンソース...
FileZilla Serverをサーバーにインストールすると、425データ接続を開けない問題が発生...
数日前、私のウェブサイトがいくつかの IP アドレスから大量の悪意のある標的型スキャンを受け、ブルー...