Vue詳細の$dataの詳細
15362 ワード
前言
$dataは、Vueインスタンスのインスタンス属性であり、Vueインスタンスが観察するデータオブジェクトを表す.実際にはVue公式サイトではこの部分について詳しく説明していますが、ここでは後述しません(具体的には公式サイトの説明Vueオプション/データを参照してください).この文章はソースレベルから$dataの背後にある論理を整理し、実際には問題です.
属性nameが存在すると仮定し、vm.$を変更する理由data.nameとvm.nameは同じ効果を達成できますか?
インスタンス属性$data
属性nameが存在すると仮定し、vm.$を変更する理由data.nameとvm.nameは同じ効果を達成できますか?
この問題を出発点として,dataにnameが存在すると仮定すると,実際にはdata初期化のソースコード論理に注目する.以前の記事(Vueインスタンス作成のdata処理とマウント)では、こちらの処理ロジックについて整理していましたが、実際にdataの処理はソースロジックがinitData関数にあり、ソースコードは具体的には以下の通りです.
InitData関数の具体的な論理は、次のような部分に分けられます. data属性がオブジェクトであるか関数であるかを判断して関連処理を行うが、最終的な結果が通常のオブジェクトであることを保証する .データオブジェクトdataのすべての属性を取得するkey遍歴処理(methods、propsに同名属性&proxy関数が存在するかどうかを検証) observeを呼び出してdata内のすべての属性およびサブ属性に対してデータハイジャック を行う.
私たちはVueがObjectを通過していることを知っています.definePropertyは、データハイジャックを実現するために使用されます.この方法の構文は、次のとおりです.
この方法では、オブジェクトのプロパティのみがハイジャックされ、次の3つの問題が発生します.問題1:属性はオブジェクトであり、現在のハイジャックオブジェクトのサブオブジェクト属性をハイジャックできない可能性がある 問題2:ダイナミックに追加できないプロパティ 問題3:オブジェクトに直接値を再割り当てた場合の の処理方法
Vueの問題1に対する処理:再帰ハイジャック
問題1の場合、Vueソースコードには再帰処理が採用され、すべてのサブオブジェクト属性に対してデータハイジャックが行われる.ソースコードでは実際にはdefineReactive$$1でobserve関数を複数回呼び出して実現され、defineReactive$$1はdataをデータハイジャック処理する関数である.
Vueの問題2に対する処理:追加のAPI
オブジェクトに動的に追加できない属性をデータブロックできないという問題に対して、Vue内部には以下のAPIが提供される. Vue.set(target, prop, value) vm.$set(target, prop, value):Vue.setの別名は です
以前、いくつかのプロジェクトCode ReviewでObjectが使用されていました.assignでプロパティを動的に追加するのも無理です.
Vueの問題3に対する処理:多層エージェント
Vueを使用すると、オブジェクト全体の再割り当てが有効になります.一般的な2つの方法があります.
上記の2つの方法の本質は、objオブジェクトに対する再付与処理である.なぜプロパティを動的に追加できずに再割り当てすればよいのでしょうか.これは、Vueソース内のdataに対する多層エージェントに依存する.実際にデータオブジェクトdataの場合、Vueインスタンスには$data,_が存在するDataという2つの同じ意味の属性は,多層エージェントもこの2つの属性と組み合わせて実現される.
$dataのハイジャック
$dataのデータハイジャックの具体的な処理はstateMixinで、主な論理は以下の通りである.
上の論理から分かる:vm.$dataはプロトタイプチェーン上のVueを呼び出す.prototype.$data,vm.$data.propは実際にはvm.data.prop.
_dataのハイジャック
_Dataのデータハイジャックの具体的な処理はinitDataの中で論理の中でproxy関数の呼び出しを遍歴して、具体的な論理は以下の通りです:
コードロジックがはっきりしているのはObjectを呼び出すことです.definePropertyですが、target、sourceKeyプロパティが重要です.ソースコールは次のとおりです.
このことからvmが分かる.propはvm.を呼び出します.data.prop.
まとめ
ソースコードのオプションdataは実際にはVueインスタンスで対応している_data内部属性、Vue対vm.$data.prop、vm.Propはデータハイジャックを行い、最下位は呼び出しです.dataオブジェクトのプロパティ.
$dataは、Vueインスタンスのインスタンス属性であり、Vueインスタンスが観察するデータオブジェクトを表す.実際にはVue公式サイトではこの部分について詳しく説明していますが、ここでは後述しません(具体的には公式サイトの説明Vueオプション/データを参照してください).この文章はソースレベルから$dataの背後にある論理を整理し、実際には問題です.
属性nameが存在すると仮定し、vm.$を変更する理由data.nameとvm.nameは同じ効果を達成できますか?
インスタンス属性$data
属性nameが存在すると仮定し、vm.$を変更する理由data.nameとvm.nameは同じ効果を達成できますか?
この問題を出発点として,dataにnameが存在すると仮定すると,実際にはdata初期化のソースコード論理に注目する.以前の記事(Vueインスタンス作成のdata処理とマウント)では、こちらの処理ロジックについて整理していましたが、実際にdataの処理はソースロジックがinitData関数にあり、ソースコードは具体的には以下の通りです.
function initData (vm) {
var data = vm.$options.data;
data = vm._data = typeof data === 'function'
? getData(data, vm)
: data || {
};
if (!isPlainObject(data)) {
data = {
};
warn(
'data functions should return an object:
' +
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
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関数の具体的な論理は、次のような部分に分けられます.
私たちはVueがObjectを通過していることを知っています.definePropertyは、データハイジャックを実現するために使用されます.この方法の構文は、次のとおりです.
Object.defineProperty(obj, prop, descriptor)
この方法では、オブジェクトのプロパティのみがハイジャックされ、次の3つの問題が発生します.
Vueの問題1に対する処理:再帰ハイジャック
問題1の場合、Vueソースコードには再帰処理が採用され、すべてのサブオブジェクト属性に対してデータハイジャックが行われる.ソースコードでは実際にはdefineReactive$$1でobserve関数を複数回呼び出して実現され、defineReactive$$1はdataをデータハイジャック処理する関数である.
Vueの問題2に対する処理:追加のAPI
オブジェクトに動的に追加できない属性をデータブロックできないという問題に対して、Vue内部には以下のAPIが提供される.
以前、いくつかのプロジェクトCode ReviewでObjectが使用されていました.assignでプロパティを動的に追加するのも無理です.
Vueの問題3に対する処理:多層エージェント
Vueを使用すると、オブジェクト全体の再割り当てが有効になります.一般的な2つの方法があります.
// 1
this.obj = {
a : 1};
// 2
this.obj = Object.assign({
}, this.obj, {
b: 1});
上記の2つの方法の本質は、objオブジェクトに対する再付与処理である.なぜプロパティを動的に追加できずに再割り当てすればよいのでしょうか.これは、Vueソース内のdataに対する多層エージェントに依存する.実際にデータオブジェクトdataの場合、Vueインスタンスには$data,_が存在するDataという2つの同じ意味の属性は,多層エージェントもこの2つの属性と組み合わせて実現される.
$dataのハイジャック
$dataのデータハイジャックの具体的な処理はstateMixinで、主な論理は以下の通りである.
var dataDef = {
};
dataDef.get = function () {
return this._data };
dataDef.set = function () {
warn(
'Avoid replacing instance root $data. ' +
'Use nested data properties instead.',
this
);
};
Object.defineProperty(Vue.prototype, '$data', dataDef);
上の論理から分かる:vm.$dataはプロトタイプチェーン上のVueを呼び出す.prototype.$data,vm.$data.propは実際にはvm.data.prop.
_dataのハイジャック
_Dataのデータハイジャックの具体的な処理はinitDataの中で論理の中でproxy関数の呼び出しを遍歴して、具体的な論理は以下の通りです:
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ですが、target、sourceKeyプロパティが重要です.ソースコールは次のとおりです.
proxy(vm, "_data", key);
このことからvmが分かる.propはvm.を呼び出します.data.prop.
まとめ
ソースコードのオプションdataは実際にはVueインスタンスで対応している_data内部属性、Vue対vm.$data.prop、vm.Propはデータハイジャックを行い、最下位は呼び出しです.dataオブジェクトのプロパティ.