序文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クエリ問題を解決します
目次序文XA プロトコルMySQL XA で分散トランザクションを実装する方法序文MySQL が単一...
実行後、一部の Docker コンテナが終了することがあります。原因を調べるには、Docker コン...
この記事では、画像のフェードインとフェードアウトを実現するためのjsの具体的なコードを参考までに紹介...
目次ヘッドレスブラウザとは何ですか?なぜ「ヘッドレス」ブラウザと呼ばれるのでしょうか?ヘッドレスブラ...
MySQL の行から列への操作いわゆる行から列への操作は、テーブルの行情報を列情報に変換することです...
注: このデモはミニプログラム環境でテストされており、他の h5 および pc Web ページにも適...
Nginx (エンジン x) は、高性能な HTTP およびリバース プロキシ サーバーであり、IM...
目次事前準備展開ターゲットDocker環境構築クラウドサーバーに接続Docker環境をインストールす...
目次1. グローバルに登録されたコンポーネント2. グローバルカスタム指示vue 、新しいプラグイン...
目次1. タイトル2. コード3. 結果IV. 結論1. タイトルテキスト ボックスに誕生日の値を入...
早速ですが、デモ画像をご紹介します。実装されている機能は、左側に凡例、右側にウォーターフォール チャ...
目次1. クラス1.1 コンストラクタ() 1.2 ゲッターとセッター1.3 これ1.4 静的プロパ...
目次1. 配列誘導1. 文字列を配列に分割する2. コレクションとマップを新しい配列に変換する3. ...
1. 基本構造:コードをコピーコードは次のとおりです。 <!DOCTYPE html PUBL...
序文CSS で水平方向と垂直方向に中央揃えする方法はたくさんあります。この記事で紹介する方法は非常に...