序文以前、defineProperty を紹介したとき、オブジェクトの変更のみを監視でき、配列の変更は監視できないことを説明しました。 この記事では、配列の変更を監視する方法を説明します。 中心的なアイデア: 元の配列を変更する方法を見つけ、それらのメソッドを乗っ取る。 上記の文章は非常に重要です。先に進む前に必ず 3 回読んで覚えておいてください。 元の配列を変更するためによく使用されるメソッドには、push、pop、shift、unshift、reverse、sort、splice などがあります。 つまり、これらのメソッドは配列のエントリを変更します。 配列インスタンスと配列プロトタイプの間に新しいプロトタイプを追加するArray.prototype を直接変更することは非常に危険です。 考え方を変えて、既存の配列プロトタイプをコピーし、その中のメソッドを変更しますが、ここではプロトタイプ上のメソッドは列挙可能ではないため、コピーできません。 では、考え方を変えてみましょう。配列と配列のプロトタイプの間にプロトタイプを挿入して、プロトタイプ チェーン (配列 => 新しいプロトタイプ => 配列のプロトタイプ) を形成します。次に、同じ名前のメソッドを新しいプロトタイプに追加できます。 まず擬似コードを使用して理解します。 // 疑似コード let arr = []; arr.__proto__ = 新しいプロトタイプ; newPrototype.__proto__ = Array.prototype; // 次に、新しいプロトタイプに同じ名前のメソッドを追加できます。newPrototype.push = xxx; 実際のコードは以下のようになります。コアではObject.createを使用しています。 // Object.create は新しいオブジェクトを返します。新しいオブジェクトの __proto__ は渡されるパラメーターです。 newPrototype = Object.create(Array.prototype); を作成します。 // 次に、新しいプロトタイプに同じ名前のメソッドを追加できます。newPrototype.push = xxx; // 監視する配列。新しいプロトタイプをバインドするだけです。let arr = []; arr.__proto__ = 新しいプロトタイプ; プッシュを例に挙げると、プッシュをハイジャックする新しいプロトタイプのプッシュ メソッドを書き換えるだけで、古いプッシュを実行するだけでなく、他の操作も実行できます。 newPrototype = Object.create(Array.prototype); を作成します。 // 新しいプロトタイプに同じ名前のプッシュを追加します newPrototype.push = function(...args) { // セマンティック this curArr = this とします。 console.log("push が使用されています"); //最後に、元のプッシュが実行されます Array.prototype.push.call(curArr, ...args) を返します。 }; // 監視する配列。新しいプロトタイプをバインドするだけです。let arr = []; arr.__proto__ = 新しいプロトタイプ; // pushが実行されると、arr.push(1)が出力されます。 他のメソッドも同様です。他のメソッドを書いてみてください 他の方法のハイジャック他のメソッドもロジックが同じであり、直接走査できるため、一緒に記述されます。 newPrototype = Object.create(Array.prototype); を作成します。 メソッドを ["push"、"pop"、"shift"、"unshift"、"reverse"、"sort"、"splice"] とします。 メソッド.forEach(メソッド => { newPrototype[メソッド] = function(...args) { console.log(`${method} が使用されました`); Array.prototype[method].call(this, ...args) を返します。 }; }); // 監視する配列。新しいプロトタイプをバインドするだけです。let arr = []; arr.__proto__ = 新しいプロトタイプ; // 実行するとarr.push(1)が出力されます。 arr.pop(); 配列内に配列項目がある場合は、それらも監視する必要があります。ここで配列内に配列が存在する場合、配列内の各項目を走査する必要があります。配列の場合でも、新しいプロトタイプを指す必要があります。 はい、再帰が使用されます。 newPrototype = Object.create(Array.prototype); を作成します。 メソッドを ["push"、"pop"、"shift"、"unshift"、"reverse"、"sort"、"splice"] とします。 メソッド.forEach(メソッド => { newPrototype[メソッド] = function(...args) { console.log(`${method} が使用されました`); Array.prototype[method].call(this, ...args) を返します。 }; }); 関数 observeArr(arr) { // これは条件付き制限と再帰終了条件の両方です if (!Array.isArray(arr)) { 戻る; } // 配列全体が新しいプロトタイプを指します arr.__proto__ = newPrototype; // 配列内の各項目は、配列の場合は、新しいプロトタイプも指します。 arr.forEach(Arr を観察します); } // 監視する配列。新しいプロトタイプをバインドするだけです。let arr = [[1, 2, 3]]; 観測Arr(arr); // 実行するとarr[0].push(1)が出力されます。 arr[1].pop(); 配列に追加された新しい項目は、配列の場合は新しいプロトタイプを指す必要があります。要素を追加できるメソッド: push unshift splice。 新しく追加された要素を見つけると、配列も新しいプロトタイプを指すようになります newPrototype = Object.create(Array.prototype); を作成します。 メソッドを ["push"、"pop"、"shift"、"unshift"、"reverse"、"sort"、"splice"] とします。 メソッド.forEach(メソッド => { newPrototype[メソッド] = function(...args) { console.log(`${method} が使用されました`); 挿入します。 スイッチ(メソッド){ ケース「プッシュ」: ケース「unshift」: 挿入された = 引数; 壊す; ケース「スプライス」: 挿入 = args.slice(2); 壊す; デフォルト: 壊す; } 挿入 && observeArr(挿入); Array.prototype[method].call(this, ...args); を返します。 }; }); 関数 observeArr(arr) { // これは条件付き制限と再帰終了条件の両方です if (!Array.isArray(arr)) { 戻る; } // 配列全体が新しいプロトタイプを指します arr.__proto__ = newPrototype; // 配列内の各項目は、配列の場合は新しいプロトタイプも指します。 arr.forEach(Arr を観察します); } // これをエクスポートすると、他のファイルでも使用しやすくなります export default observeArr; // 監視する配列。新しいプロトタイプをバインドするだけです。let arr = []; 観測Arr(arr); addItem = [1, 2, 3]とします。 arr.push(アイテムを追加); // 実行するとaddItem.push(1)が出力されます。 アイテムを追加します。 オブジェクトと配列を監視するためのdefinePropertyの併用これで、オブジェクトを監視するメソッドと配列を監視するメソッドができました。この 2 つを組み合わせることで、配列内のオブジェクトとオブジェクト内の配列を監視できます。 監視配列と監視オブジェクトは、後で使用するために別のファイルに書き込むことができます。 直接コード実行を容易にするために、これらはここにまとめられています。 /** * observeArr 部分**/ // 新しいプロトタイプを生成します。let newPrototype = Object.create(Array.prototype); メソッドを ["push"、"pop"、"shift"、"unshift"、"reverse"、"sort"、"splice"] とします。 // 上記のメソッドを新しいプロトタイプに追加して、methods.forEach(method => { newPrototype[メソッド] = function(...args) { console.log(`${method} が使用されました`); 挿入します。 スイッチ(メソッド){ ケース「プッシュ」: ケース「unshift」: 挿入された = 引数; 壊す; ケース「スプライス」: 挿入 = args.slice(2); 壊す; デフォルト: 壊す; } 挿入 && observeArr(挿入); Array.prototype[method].call(this, ...args); を返します。 }; }); 関数 observeArr(arr) { // 新しい! ! !オブジェクトの場合は、オブジェクトを使用する必要があります if (Object.prototype.toString.call(arr) === "[object Object]") { 観測オブジェクト(arr) 戻る; } Array.isArray(arr) の場合 { // 配列全体が新しいプロトタイプを指します arr.__proto__ = newPrototype; // 配列内の各項目は、配列の場合は新しいプロトタイプも指します。 arr.forEach(Arr を観察します); } // オブジェクトでも配列でもない場合は何もしません} /** * observeObj 部分**/ 関数 observeObj(obj) { // パラメータ制限を追加します。オブジェクトのみがハイジャック可能で、これは再帰の終了条件でもあります。if (typeof obj !== "object" || obj == null) { 戻る; } // 新しい! ! !配列は処理のために配列に渡されます if (Array.isArray(obj)) { 観測Arr(obj); 戻る; } // オブジェクトの場合のみ再帰を開始する for (let key in obj) { // obj.hasOwnProperty を直接使用すると非標準のプロンプトが表示されます if (Object.prototype.hasOwnProperty.call(obj, key)) { obj を observeKey します。 // ここで、属性の属性値がハイジャックされます。オブジェクトでない場合は、observeObj(obj[key]) に影響を与えずに直接返されます。 } } obj を返します。 } 関数 observeKey(obj, key) { 値をobj[キー]とします。 Object.defineProperty(obj, キー, { 得る() { console.log("プロパティを読み取り", 値); 戻り値; }, set(新しい値) { console.log("プロパティを設定する", newValue); 値 = 新しい値; } }); } /** * デモを試す**/ データ = {a: 1、b: [1、2、{c: 2 }] }とします。 observeObj(データ); データ.a = 2; データ.b.push([2, 3]); arr = [{ a: "配列内のオブジェクト" }, 3, 4]とします。 観測Arr(arr); arr[0].a = 3; 欠陥もちろん、メソッドを使わずに配列を変更することもできます。たとえば、length属性を使用して配列を削除したり、arr[0]=xxxを使用して配列を直接変更したりできます。 ただし、配列の変更は、「push」、「pop」、「shift」、「unshift」、「reverse」、「sort」、「splice」を使用する場合にのみ検出できます。 これも Vue の欠陥です。もちろん、新しいバージョンのプロキシではこの欠陥は解消されます。 なのでvueを使うときは上記の方法で配列を操作してみてください~~~ 注: 配列のすべてのプロパティとメソッドを表示するコンソールに dir([]) と入力すると、配列のすべてのプロパティとメソッドが表示されます。 具体的な使用方法については、mdnに直接アクセスし、サイドバーをクリックして対応する方法を確認してください。 要約するJavaScript で配列の変更を監視する方法についての記事はこれで終わりです。JS による配列の変更の監視に関するより関連性の高いコンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
<<: Centos8 でローカル Web サーバーを構築するための実装手順
>>: mysql 8.0.16 winx64 および Linux でルート ユーザーのパスワードを変更する方法
yum か rpm か? yum によるインストール方法は非常に便利ですが、公式サイトから MySQ...
今日、Nginxを使っていたら500エラーが発生しました。エラーコードを検索してみんなに共有しました...
目次要件: 進行中のアクティビティ データを照会する次のSQLクエリは、上記の4つの要件を満たし、タ...
目次1.DB、DBMS、SQL 2. データベースの特徴3. SQL分類4. MySQLを起動および...
cli3 でビルドされた vue プロジェクトは、ゼロ構成ファイルとして知られています。パッケージ化...
目次1. はじめに1. インデックスとは何ですか? 2. インデックスはなぜ必要なのでしょうか? 2...
非準拠データがデータベースに入るのを防ぐために、ユーザーがデータを挿入、変更、削除、その他の操作を行...
序文WeChat アプレット開発 (ネイティブ wxml、wxcss) で、{{ }} 内で直接メソ...
この記事では、階段スライド効果を実現するためのjQueryの具体的なコードを参考までに紹介します。具...
目次外部キーテーブルの関係を決定する方法テーブル関係を作成する方法1対多の関係 - 従業員テーブルと...
SFTPの概念sftp は、安全なファイル転送プロトコルである Secure File Transf...
MySQL の多くのテーブルには、NULL が列のデフォルト属性であるため、アプリケーションが NU...
ログインを提供し、ユーザー情報データインターフェースを取得するapi/user.js内 '@...
目次1. 新しいプロジェクトを作成する2. 依存関係を追加する3. SpringコンテナにDrive...
例示するMySql Community Edition は、5.7.11 以降、テーブルベースのデー...