ホームページ >ウェブフロントエンド >jsチュートリアル >Vue が配列の変更を検出できないのはなぜですか?その理由は次のとおりです
問題の説明: Vue は Object.defineProperty を通じてデータ変更を検出します。そのため、配列の追加操作を監視できないことは理解できます。この検出とバインド操作はコンストラクター内のすべてのプロパティに対して行われているためです。
ただし、公式テキスト: JavaScript の制限により、Vue は次の変更された配列を検出できません:
インデックスを使用して項目を直接設定する場合、たとえば: vm.items[indexOfItem] = newValue
長さを変更する場合例: vm.items.length = newLength
この文はどういう意味ですか? Object.defineProperty がインデックス プロパティを通じてプロパティのアクセサー プロパティを設定できることをテストしましたが、なぜそれを監視できないのでしょうか?
配列の長さは可変であるため、長さが 5 であってもインデックス 4 を持たない可能性があるとフォーラムの一部の人が言っています。長さを変更する場合、この答えはどこから来たのかを尋ねたいと思います。新しい要素は最後に追加され、その値は未定義ですが、その値はインデックスを介して取得することもできます。なぜ「インデックス 4 を持たない可能性がある」と呼ばれるのでしょうか。
配列の長さはわかったので、すべての要素を走査して set を追加し、インデックス属性を介してすべての要素にアクセスできないのはなぜでしょうか?同時にビューを更新できるのでしょうか?
強いて言えば、パフォーマンスの問題を考慮すると、要素の内容に意味のある値が 4 つしかないが、長さが確かに 1000 であると仮定すると、1000 個の要素に対して検出操作を実行することは不可能です。しかし、公式はそれが JS の制限によるものだと言いました。この制限が何なのか知りたいです。この問題の解決にご協力いただき、誠にありがとうございます
この問題に直面して、私が言いたいのは、まず第一に、長さが 1000 の配列であっても要素が 4 つだけであるということは必ずしもパフォーマンスに影響を与えるわけではないということです。 js for ループに加えて、データの走査には forEach、map、filter、some などが含まれます。ただし、for ループ (for、for...of) を除き、他の走査はすべてキー値の走査です。つまり、これらの 4 つの要素を除いて、外側の空のスペースは走査されないため、パフォーマンスの低下はありません。ループ本体に操作がない場合、パフォーマンスへの影響は無視できるためです。以下は次のような配列です。長さは 10000 ですが、要素は 2 つだけです。 for と forEach のトラバーサルをそれぞれ使用した結果: var arr = [1]; arr[10000] = 1
function a(){
console.time()
for(var i = 0;i<arr.length;i++)console.log(1)
console.timeEnd()
}
a(); //default: 567.1669921875ms
a(); //default: 566.2451171875ms
function b(){
console.time()
arr.forEach(item=>{console.log(2)})
console.timeEnd()
}
b(); //default: 0.81982421875ms
b(); //default: 0.434814453125ms
ただし、for ループで操作が実行されない場合、この 2 つの速度は次のようになります。ほぼ同じです
次に、私が言いたいのは、この制限が何なのかわからないということです (⇀‸↼‶) ╮( •́ω•̀ )╭
Object.defineProperty() メソッドが直接定義するものです。オブジェクトの新しいプロパティを追加するか、オブジェクトの既存のプロパティを変更して、オブジェクトを返します。配列のインデックスも属性なので、配列要素の変更を監視できます
var arr = [1,2,3,4] arr.forEach((item,index)=>{ Object.defineProperty(arr,index,{ set:function(val){ console.log('set') item = val }, get:function(val){ console.log('get') return item } }) }) arr[1]; // get 2 arr[1] = 1; // set 1
しかし、要素を追加すると、この新しい属性を監視していないため、リッスン イベントはトリガーされません。属性を削除する場合は true。
主な質問に戻ります。配列は監視できるのに、添字が対応するものであっても、vue は vm.items[indexOfItem] = newValue
によって引き起こされる配列要素の変更を検出できないのはなぜですか。要素が存在し、監視されていますか?
この問題を明確にするために、vue のソースコードでテストしてみました。以下は vue によるデータ監視のソースコードです: vm.items[indexOfItem] = newValue
导致的数组元素改变呢,哪怕这个下标所对应的元素是存在的,且被监听了的?
为了搞清楚这个问题,我用vue的源码测试了下,下面是vue对数据监测的源码:
可以看到,当数据是数组时,会停止对数据属性的监测,我们修改一下源码:
使数据为数组时,依然监测其属性,然后在defineReactive函数中的get,set打印一些东西,方便我们知道调用了get以及set。这里加了个简单判断,只看数组元素的get,set
然后写了一个简单案例,主要测试使用vm.items[indexOfItem] = newValue
データが配列の場合、データ属性の監視が停止することがわかります。ソース コードを変更します:
データを次のように作成します。配列を読み取るときに、引き続きそのプロパティを監視し、get と set が呼び出されたことを知ることができるように、defineReactive 関数の get と set で何かを出力します。ここに簡単な判断を追加します。配列要素の取得、set
次に、主に vm.items[indexOfItem] = newValue
を使用して配列要素を変更できるかどうかをテストする簡単なケースを作成しました。レンダリング ページ
実行ページ
最初に set が実行され、次にデータが更新され、ページが再レンダリングされ、配列が 2 回走査されていることがわかります。
でも! ! !配列は確かに応答性が高くなりました。これは、js 構文関数が配列の監視を制限しないことを意味します。
ここでは長さ 3 の配列を使用してテストしています。配列の長さを 9 に増やすと
、get を 18 回実行した後でも、要素をクリックしても配列が 2 回走査されていることがわかります。 、レンダリング時にも 2 回トラバースされます。
上記の実験により、vue で配列をレスポンシブに更新できるという結論になりましたが、なぜ Youda がこの機能を追加しなかったのかわかりません。知っている専門家がいたら教えてください。
関連記事: 関連動画:配列変更検出 - Wheat Academy Vue.js ビデオ チュートリアル
以上がVue が配列の変更を検出できないのはなぜですか?その理由は次のとおりですの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。