序文defineProperty は、データ ハイジャックを実現するための Vue の中核です。この記事では、defineProperty がどのようにプロパティ ハイジャックを実現するかを少しずつ説明します。 実際、通常、オブジェクトのプロパティはプロパティを追加または変更する方法で操作され、Object.defineProperty を使用できます。 obj = {} とします。 // 共通操作: 新しい属性を追加/変更 obj.a = 1; // は次のものと同等です: オブジェクト.defineProperty(o, "a", { 値: 1, 書き込み可能: true、 設定可能: true、 列挙可能: true }); もちろん、通常の例では、長くなりすぎるため、このようには実行しません。 しかし、defineProperty を使用すると、オブジェクトのプロパティをより正確に追加または変更できます。 記述子まず固有名詞「記述子」から始めましょう。 実際、これはオブジェクトである defineProperty の 3 番目のパラメータです。このオブジェクトには次のプロパティがあります。
知らせ! ! !
getとsetの詳細な説明
黙って3回繰り返して覚えましょう。 理解を助けるために get と set の例を書いてください。 この例をマスターする必要があります。これを理解すれば、基本的にデータハイジャックの本質を理解できるようになります。 obj = {} とします。 値を 1 にします。 オブジェクト.defineProperty(obj, "b", { 得る() { console.log("b 属性を読み取りました", 値); 戻り値; }, set(新しい値) { console.log("b プロパティを設定", newValue); 値 = 新しい値; } }); // get 関数をトリガーします。get の戻り値は属性値です // 1 コンソールにログ出力します。 // 設定関数をトリガーすると、値が 2 になります。注意してください。 ! !このとき、メモリ内の属性値は変更されていません。obj.b = 2; // ただし、プロパティ値を読み取りたい場合、必然的に get 関数がトリガーされ、プロパティ値が自然に変化します。このアイデアは本当に優れています console.log(obj.b); ここで落とし穴があります。get では読み取り操作はできません。そうしないと無限ループになります。そのため、get set が使用される場所では、常に変数が必要になります。 したがって、ここでは、変数 value の値が属性の値になります。属性を変更する場合は、value の値を変更するだけです。 この例を理解すれば、get と set の本質を理解するのに十分だと思います。 オブジェクトの属性の乗っ取り前の例を基に、ハイジャックされたオブジェクトの任意のプロパティを記述してみます。 関数 observeKey(obj, key) { 値をobj[キー]とします。 Object.defineProperty(obj, キー, { 得る() { console.log("プロパティを読み取り", 値); 戻り値; }, set(新しい値) { console.log("プロパティを設定する", newValue); 値 = 新しい値; } }); } obj = {a: 1} とします。 観測キー(obj, "a"); // a を読み取り、get 関数をトリガーします console.log(obj.a); // a を設定し、set 関数をトリガーします。obj.a = 1; オブジェクトのすべてのプロパティをハイジャックするオブジェクトのすべてのプロパティを乗っ取ろうとする 実際、それはトラバーサルです: 関数 observeObj(obj) { for (let key in obj) { // obj.hasOwnProperty を直接使用すると非標準のプロンプトが表示されます if (Object.prototype.hasOwnProperty.call(obj, key)) { obj を observeKey します。 } } obj を返します。 } 関数 observeKey(obj, key) { 値をobj[キー]とします。 Object.defineProperty(obj, キー, { 得る() { console.log("プロパティを読み取り", 値); 戻り値; }, set(新しい値) { console.log("プロパティを設定する", newValue); 値 = 新しい値; } }); } obj = {a: 1, b: 2} とします。 obj を観察します。 コンソールにログ出力します。 // a を読み取り、get 関数をトリガーします console.log(obj.a); // a を設定し、set 関数をトリガーします。obj.a = 1; オブジェクトのすべてのプロパティをハイジャックする - オブジェクトタイプのプロパティ値を含む上記には欠陥があり、属性値もオブジェクトである場合、{a:1,c:{b:1}}のように属性値をハイジャックすることはできません。 シンプル、再帰、記入するだけ。 関数 observeObj(obj) { // パラメータ制限を追加します。オブジェクトのみがハイジャック可能で、これは再帰の終了条件でもあります。if (typeof obj !== "object" || obj == null) { 戻る; } 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); 値 = 新しい値; } }); } obj = { a: 1, b: 2, c: { name: "c" } } とします。 obj を観察します。 コンソールにログ出力します。 // a を読み取り、get 関数をトリガーします console.log(obj.a); // a を設定し、set 関数をトリガーします。obj.a = 1; // トリガー設定 function obj.c.name = "d"; observeObj 関数はオブジェクトの新しいプロパティをハイジャックすることはできず、オブジェクトの既存のプロパティのみをハイジャックできることに注意してください。 definePropertyの欠点
もちろん、配列の変更は他の方法で監視できます。これは、配列変更メソッドをハイジャックすることによって実現されます。 上記の欠陥は、Vue に $set/$delete が存在する理由であり、配列が特定の方法でのみ検出できる理由でもあります。 obj = { a: 1, b: [1, 2] } とします。 obj を観察します。 // 新しい属性を追加します。obj.c = 3; // get 関数はトリガーされません console.log(obj.c); // 設定関数はトリガーされません obj.b.push(3); definePropertyはプロパティをマウントすることもできます実際、これはoptions.data.name(専門用語ではoptions.nameと略される)にアクセスして、データの属性をオプションにマウントすることです。 これは、defineProperty を使用してオプションに新しいプロパティを追加することと同じです。 // 最初に単一の属性をマウントします // options.data はソースと同等です options はターゲットと同等です 関数 proxyKey(ターゲット, ソース, キー) { Object.defineProperty(ターゲット、キー、{ // ここでsource[key]は変数値と同等なので、最も単純な例はコアのget() { ソース[キー]を返します。 }, set(新しい値) { if (newValue === source[key]) { 戻る; } ソース[キー] = 新しい値; } }); } // 属性をトラバースしてマウントする function proxyObj(target, source) { for (let key in source) { // obj.hasOwnProperty を直接使用すると非標準のプロンプトが表示されます if (Object.prototype.hasOwnProperty.call(source, key)) { proxyKey(ターゲット、ソース、キー); } } } オプション = { データ: { 名前: 1 } }; proxyObj(オプション、オプションデータ); // 1 console.log(オプション名); ちなみに、Vue の属性ハイジャックと属性のマウントの基本原則は、上記とほぼ同じです。 definePropertyはログも書き込むことができますたとえば、obj には値が頻繁に変更される属性があり、変更された値をすべて記録してログを形成したいとします。 obj = {a: 1} とします。 log = [obj.a]; とします。 値を obj.a とします。 オブジェクト.defineProperty(obj, "a", { 得る() { 戻り値; }, set(新しい値) { (新しい値 === 値) の場合 { 戻る; } 値 = 新しい値; log.push(新しい値); } }); 2 番目の引数は 0 です。 3 を 0 に する 4 を 0 にします。 // [1,2,3,4] コンソールにログを出力します。 一般的なクラスを抽出して、特定の値の変化を記録することができます。 クラスアーカイバ{ コンストラクタ() { 値を null にします。 this.archive = []; Object.defineProperty(this, "a", { 得る() { 戻り値; }, set(新しい値) { (新しい値 === 値) の場合 { 戻る; } 値 = 新しい値; this.archive.push(新しい値); } }); } } アーカイバを新しいアーカイバ()にします。 アーカイバ.a = 1; アーカイバ.a = 2; // [1,2] console.log(アーカイバ.アーカイブ); 参考文献 MDN の defineProperty 要約するJavaScript の defineProperty でプロパティ ハイジャックを実装する方法についての記事はこれで終わりです。defineProperty プロパティ ハイジャックに関するその他の関連コンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 |
<<: VMware での Ubuntu Docker のインストール (コンテナ構築)
>>: MySQLはデータベースのN+1クエリ問題を解決します
Win10はmysql5.7の解凍版をインストールします。参考までに、具体的な内容は次のとおりです...
この記事では、MySQL 8.0.12のインストールチュートリアルを参考までに紹介します。具体的な内...
目次1. 材料を準備する2. Linuxカーネルファイルをダウンロードする3. コンパイル4. TF...
初めてwampをインストールした後、すべてのサービスが正常に使用できますが、再起動するとwampのア...
以下のように表示されます。 mysql.proc から名前を選択します (db='データベー...
1. 関連概念1.1 Jenkins の概念: Jenkins は、使用されるプラットフォームに関係...
夜にMACの電源を入れたところ、突然ルートアカウントがMySQLに正常にログインできなくなったため、...
最近、VMware Horizon を導入してテストしましたが、そのコンソールにはデフォルトで ...
コンテンツ プロパティは CSS 2.1 で導入され、:before および :after 疑似要素...
-9999 ピクセルの画像置換技術は、ここ 10 年近く人気があります。テキスト要素を画像に置き換え...
では早速、コードをお見せしましょう。具体的なコードは次のとおりです。 #!/bin/bash cd ...
MySQLへのリモートアクセスを有効にするデフォルトでは、MySQL ユーザーにはリモート アクセス...
目次1 はじめに2 基本的な使い方2.1 方法2.2 計算プロパティ2.3 リスナーを見る3 3つの...
1994 年に設立された組織である W3C は、共通プロトコルの開発を促進し、それらの相互運用性を確...
以下のように表示されます。 table1 を z として更新し、table2 を zb として結合し...