Vueソース学習の2:配列の変化を傍受する
5014 ワード
前回のコードでは,配列の処理を無視し,関心が必要な部分だけに関心を持ち,配列が存在しないふりをした.
この編では配列の問題を考え始めた.
最も簡単なことから
まず、配列内のオブジェクトの変化をどのように傍受するかという問題を考えます.配列自体とその一般値を無視し、オブジェクト配列内のオブジェクトのみを考慮します.
配列を巡回し、配列内の各オブジェクトに対してobserveメソッドを呼び出します.
現実的な要求.
実際の実装では、上記の例のように簡単ではありません.公式ドキュメントでは、リスニング配列について説明しています.
Vueには、配列を観察する突然変異のセットが含まれているため、ビューの更新もトリガーされます.これらの方法は、push()、pop()、shift()、unshift()、splice()、sort()、reverse()
JavaScriptの制限のため、Vueは以下の変動の配列を検出できません:あなたが直接1つの項目のインデックスを設定する時、例えば:vm.items[indexOfItem]=newValue配列の長さを変更すると、たとえばvm.items.length = newLength
したがって,配列自体のいくつかの方法を傍受する.
よく使われる小さな関数
defは、Vueソースコード全体にわたって繰り返され、Objectを利用する.defineProperty()objで属性keyを定義します(既存の属性keyを変更することもできます):
オブジェクトにメソッドのセットを追加
オブジェクトにメソッドのセットを追加し、環境でprotoをサポートすれば簡単です.オブジェクトのprotoを直接このメソッドのセットに指さすといいです.サポートされていない場合は、このメソッドのセットを巡り、非表示属性(enumerable:false、inキーでは見つかりません):
まず簡単なものをください.
配列の変化を監視するために配列プロトタイプを擬似書き換え
公式文書で述べたように、監視が必要なのはpush()、pop()、shift()、unshift()、splice()、sort()、reverse()の7つの方法だけで、この7つの方法には2つの種類があります. push()、unshift()、splice()の3つの配列に新しい要素を追加する可能性のある方法. 残りの要素を追加しない方法.
全体を汚染するArrayを避けるために、Array.prototypeはプロトタイプのオブジェクトであり,その後そのオブジェクト自体に属性を付加し,この新規のオブジェクトをプロトタイプとしてあるいはObserverのvalueに属性として追加し,その変化を監視する目的を達成する.
次に、arrayMethodsに更新をトリガーするいくつかの方法を巡回します.
Observerの更新
上記の例のコードの注釈に従って、Observerを書き換え、両者を関連付けて配列の変化を傍受する目的を達成する.
参考資料:vue初期ソース学習シリーズの2:配列の変化をどのように傍受するか
この編では配列の問題を考え始めた.
最も簡単なことから
まず、配列内のオブジェクトの変化をどのように傍受するかという問題を考えます.配列自体とその一般値を無視し、オブジェクト配列内のオブジェクトのみを考慮します.
配列を巡回し、配列内の各オブジェクトに対してobserveメソッドを呼び出します.
// ,
var Observer = function Observer(value) {
this.value = value;
this.dep = new Dep();
// ,
if(Array.isArray(value)) {
this.observeArray(value);
} else {
this.walk(value);
}
};
Observer.prototype.observeArray = function observeArray(items) {
// , getter、setter
for (var i = 0, l = items.length; i < l; i++) {
observe(items[i]);
}
};
現実的な要求.
実際の実装では、上記の例のように簡単ではありません.公式ドキュメントでは、リスニング配列について説明しています.
Vueには、配列を観察する突然変異のセットが含まれているため、ビューの更新もトリガーされます.これらの方法は、push()、pop()、shift()、unshift()、splice()、sort()、reverse()
JavaScriptの制限のため、Vueは以下の変動の配列を検出できません:あなたが直接1つの項目のインデックスを設定する時、例えば:vm.items[indexOfItem]=newValue配列の長さを変更すると、たとえばvm.items.length = newLength
したがって,配列自体のいくつかの方法を傍受する.
よく使われる小さな関数
defは、Vueソースコード全体にわたって繰り返され、Objectを利用する.defineProperty()objで属性keyを定義します(既存の属性keyを変更することもできます):
function def(obj, key, val, enumerable) {
Object.defineProperty(obj, key, {
value: val,
// boole , , false
enumerable: !!enumerable,
writable: true,
configurable: true
});
}
オブジェクトにメソッドのセットを追加
オブジェクトにメソッドのセットを追加し、環境でprotoをサポートすれば簡単です.オブジェクトのprotoを直接このメソッドのセットに指さすといいです.サポートされていない場合は、このメソッドのセットを巡り、非表示属性(enumerable:false、inキーでは見つかりません):
var hasProto = '__proto__' in {};
var augment = hasProto ? protoAugment : copyAugment;
function protoAugment(target, src) {
target.__proto__ = src;
}
function copyAugment(target, src, keys) {
for(var i = 0; i < keys.length; i++) {
var key = keys[i];
def(target, key, src[key]);
}
}
まず簡単なものをください.
var arrayPush = {};
(function(method){
var original = Array.prototype[method];
arrayPush[method] = function() {
// this
console.log(this);
return original.apply(this, arguments)
};
})('push');
var testPush = [];
testPush.__proto__ = arrayPush;
// , this testPush
// []
testPush.push(1);
// [1]
testPush.push(2);
配列の変化を監視するために配列プロトタイプを擬似書き換え
公式文書で述べたように、監視が必要なのはpush()、pop()、shift()、unshift()、splice()、sort()、reverse()の7つの方法だけで、この7つの方法には2つの種類があります.
全体を汚染するArrayを避けるために、Array.prototypeはプロトタイプのオブジェクトであり,その後そのオブジェクト自体に属性を付加し,この新規のオブジェクトをプロトタイプとしてあるいはObserverのvalueに属性として追加し,その変化を監視する目的を達成する.
var arrayProto = Array.prototype;
var arrayMethods = Object.create(arrayProto);
次に、arrayMethodsに更新をトリガーするいくつかの方法を巡回します.
['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function(method) {
//
var original = arrayProto[method];
// arrayMethods method, method ( )
// arrayMethods
def(arrayMethods, method, function mutator() {
var arguments$1 = arguments;
var i = arguments.length;
var args = new Array(i);
// arguments
// [].slice.call(arguments)?
while(i--) {
args[i] = arguments$1[i];
}
var result = original.apply(this, args);
// arrayMethods Observer value , this Observer value
// , Observer, value Observer ,__ob__,
var ob = this.__ob__;
//
var inserted;
//
switch(method) {
case 'push':
inserted = args;
break;
case 'unshift':
inserted = args;
break;
case 'splice':
// splice
inserted =args.slice(2);
break;
}
if(inserted) {
// getter、setter
ob.observerArray(inserted);
}
//
ob.dep.notify();
return result;
});
};
var arrayKeys = Object.getOwnPropertyNames(arrayMethods);
Observerの更新
上記の例のコードの注釈に従って、Observerを書き換え、両者を関連付けて配列の変化を傍受する目的を達成する.
var Observer = function Observer(value) {
this.value = value;
this.dep = new Dep();
def(value, '__ob__', this);
// ,
if(Array.isArray(value)) {
var argument = hasProto ? protoAugment : copyAugment;
argument(value, arrayMethods, arrayKeys);
this.observeArray(value);
} else {
this.walk(value);
}
};
参考資料:vue初期ソース学習シリーズの2:配列の変化をどのように傍受するか