definePropertyおよびgetter、setterの理解

4950 ワード

vueはgetterとsetterでデータモニタリングを実現しているとよく耳にしますが、getterとsetterはいったい何なのか、definePropertyとはどんな関係なのか、普段はどんな役に立つのでしょうか.本文はみんなのために一つ一つ来ます.
オブジェクトのプロパティ
一貫した「浅いから深い」行文の原則に従って、まず対象の属性を復習します.オブジェクトには独自の属性とプロトタイプ上の属性があることを知っています.objを通過することができます.keyはこのようにアクセスします.
オブジェクトのプロパティを設定/変更するのも簡単ですobj.key='value'でいいです.keyがプロトタイプに存在する場合、プロトタイプを変更するのではなく、オブジェクト自体に値が設定されます.
また、プロトタイプのプロパティは、for inによって「うっかり」遍歴される場合があります.たとえば、次のコードです.
var arr = [1,2,3];
arr.__proto__.test = 4;
for(i in arr){
    console.log(arr[i]);
}
//  :1234

だから私たちは普通for inを使う時hasOwnPropertyの判断を加えたり、for inを捨てたり、forEachを使ったりします.
認識defineProperty
definePropertyは、オブジェクトに属性を定義するか、既存の属性の値を変更し、その属性の記述子を設定することによって、Objectにマウントする方法です.このメソッドは、変更されたオブジェクトを返します.
後半文の役割がなければobjと同じです.key='value'という付与文は変わらない.彼の完全な文法はこうです:Object.defineProperty(obj, prop, descriptor)obj:ターゲットオブジェクトprop:プロパティ名descriptor:プロパティ記述子
最初の2つは言うまでもなく、第3のパラメータを重点的に理解する必要があります.属性記述子は、その属性のいくつかの特性を定義するために使用されます.具体的には、データ記述子(data descriptor)、アクセス記述子(accessor descriptor)の2種類に分類する.
この2つの記述子には、2つの必須オプションがあります.
  • configurableは、文字通り「構成可能」を表し、trueである場合、属性の記述子を変更し、deleteによって削除することができることを意味する.同様にfalseの場合、definePropertyを呼び出して記述子を変更することはできません.deleteで削除することはできません.
  • enumerableは、文字通り「列挙可能」を表し、trueである場合、この属性を反復器に列挙することができることを意味する.例えばfor inまたはObjectを用いる.keys.

  • 次はデータ記述子(data descriptor)です.2つあります.
  • valueこれがその属性の値であるobjを通過する.keyアクセス時に戻ります.どのjsデータ型でも使用できます(number,string,object,functionなど).
  • writableこれもよく理解され、その属性が書けるかどうかを示しています.falseの場合、属性は任意の付与文で書き換えられません.しかし、definePropertyを呼び出してvalueを変更することもできます.もちろんconfigurableがtrueであることが前提です.

  • あとはアクセス記述子です.まず関門を売って2つの注意事項を話します.
    記述子のプロトタイプとデフォルト
    一般的にdescriptorオブジェクトを作成し、definePropertyメソッドに渡します.次のようになります.
    var descriptor = {
        writable: false
    }
    Object.defineProperty(obj, 'key', descriptor);

    この場合はリスクがあり、descriptorのプロトタイプに関連する特性がある場合は、プロトタイプチェーンを介してアクセスされ、keyの定義に計算されます.例:
    descriptor.__proto__.enumerable = true;
    Object.defineProperty(obj, 'key', descriptor);
    Object.getOwnPropertyDescriptor(obj,'key'); //   enumerable true

    このような事故を避けるために、Objectを使用することを公式に提案した.freezeオブジェクトをフリーズするか、Objectを使用します.create(null)は、プロトタイプを含まない純粋なオブジェクトを作成して使用します.
    次の注意点はデフォルト値です.まず、obj.key="value"のような一般的な付与文がどのような記述子を生成するかを考えます.
    Objectを使用できます.getownPropertyDescriptorは、プロパティの記述子を返します.
    obj = {};
    obj.key = "value";
    Object.getOwnPropertyDescriptor(obj, 'key');
    /*  
    {
        configurable:true,
        enumerable:true,
        value:"value",
        writable:true,
    }
    */

    これも複合的に予想され、文に追加された属性を付与することによって、関連記述子はtrueであり、書き込み可能構成は列挙可能である.しかしdefinePropertyで定義されたプロパティを使用すると、デフォルト値はそうではありません.configurable:false enumerable:false writable:false value:undefined
    デフォルトがfalseにならないように、使用するときは記述子を全部書いてください.
    getterとsetter
    getterとsetterとは実は2つの概念であり,このような属性はない.これに対応する2つのアクセス記述子(access descriptor):
  • getプロパティにアクセスすると自動的に呼び出され、関数の戻り値がプロパティのvalueになります.デフォルトはundefinedです.

  • valueもget関数もあると思うかもしれませんが、属性の値は何ですか?では、あなたは考えすぎて、このような状況は定義の時に直接間違っていて、自分の論理は矛盾していますか.
  • setプロパティに値を割り当てると自動的に呼び出され、新しい値がパラメータとして入力されます.

  • ここを見ると目の前が明るくなるかもしれませんが、属性に値を割り当てると自動的に関数が実行され、データの変化を監視してmvmの双方向バインドを実現できるのではないでしょうか.実はvueのデータモニタリングに使われる核心原理はこれです.knockoutを使ったことがあるともっと深く感じるかもしれませんが、knockoutはIE 6で双方向バインドをサポートすることができます.つまり、属性値を関数タイプに強制するには、手動で関数を実行しなければ値を得ることができません.
    幸いなことに、ブラウザのデフォルトのサポートがあり、ES 5はgetter、setterをサポートし始めました.現在、モバイル側は基本的に完全に利用でき、pc側はIE 9+が必要です.
    実際の応用
    こんな使いやすい方法は、私たちも普段あまり使わないようですね.ビジネスコードを書くには確かに少ないかもしれませんが、共通のモジュールを書くか、フレームワークを書くかで使用することができます.
    たとえば、共通モジュールを書くと、windowにグローバル属性が掛けられ、他の場所でうっかりこの属性を上書きしたくない場合は、definePropertyでその属性を書き込み不可、構成不可にすることができます.私たちのプロジェクトのコードを貼り付けます.
    //         
    for(let key in methods){
        if(methods.hasOwnProperty(key)){
            Object.defineProperty(WIN, key, {
                value        : methods[key]
            });
        }
    }

    もう一つの用途は、あなた自身が悪いことをしたいということです.他の人が書いたコードを上書きします.例えば、chromeプラグインを書いてページをブラシします.あるいはブラウザの情報を改ざんしたいと思っています.
    ブラウザのuserAgentを変更したい場合は、navigator.userAgent = 'iPhoneX'と直接書きます.userAgentを出力してみると、変更されていないことがわかります.これはなぜですか.この行のコードを見てみましょう.
    Object.getOwnPropertyDescriptor(window, 'navigator');
    //  
    {
        configurable:true,
        enumerable:true,
        get:ƒ (),
        set:undefined
    }

    理由は見つかりました.navigatorにはsetterがあり、値を取るたびにこのset関数を実行して戻ります.しかし、良いニュースは何ですか?configurableはtrueです.これはdefinePropertyでこの属性を変更できることを意味します.コードはかなり簡単です.
    Object.defineProperty(navigator, 'userAgent', {get: function(){return 'iphoneX'}})
    console.log(navigator.userAgent); //  iphoneX

    ほら、ブラウザuserAgentを改ざんする方法を教えてあげました.
    転載先:https://www.cnblogs.com/lvdabao/p/7989238.html