JavaScriptのゲッターとセッター

多くの人々は、多くのプログラミング言語でゲッターとセッターが何であるかを知っています。 JavaScriptにはこれらのすばらしいものもありますが、最近になってそのことを知りました(私は教育を受けていません)。 getSomeProperty()/setSomeProperty(...)メソッドだけでなく、もっと興味深い実装-ハンドラー関数が呼び出されるときに変更する疑似属性についても説明します。



明らか


最も簡単な方法は、getSomeProperty()/ setSomeProperty(...):
function MyObject(newVal) {
this ._secretProperty = newVal;
}
MyObject.prototype = {
getSecretProperty: function () {
return this ._secretProperty;
},
setSecretProperty: function (newVal) {
return this ._secretProperty = newVal;
}
}

* This source code was highlighted with Source Code Highlighter .

これは最も単純で最も明白なケースです。 しかし、最悪です。 これにデータを保存することで、「邪悪なハッカー」からデータを隠しません。 そして、そうすることはかなり可能です:
var obj = new MyObject();
obj._secretProperty = '-! - , !' ;
// setSecretProperty. -- :)

* This source code was highlighted with Source Code Highlighter .


ステップ2:コンストラクタークロージャーでデータを非表示にする


function MyObject(newVal) {
var _secretProperty = newVal;
this .getSecretProperty = function () {
return _secretProperty;
}
this .setSecretProperty = function (newVal) {
return _secretProperty = newVal;
}
}


* This source code was highlighted with Source Code Highlighter .

すべて、データは非表示であり、 this ._secretPropertyすでにundefinedです。 悪意のあるハッカーだ!
ただし、コンピューターのメモリを少し犠牲にしました。プロトタイプではなくコンストラクターでメソッドを作成し、このタイプの新しいインスタンスごとにそれらにメモリを割り当てます。 しかし、あなたはこれを心配することはできません。 このようなオブジェクトの100%は1,000,000にはなりません。 そして、最新のPCのメモリ容量により、このような贅沢が可能になります。 例:
var obj = new MyObject(42);
alert(obj._secretProperty); // undefined
alert(obj.getSecretProperty()); // 42
obj._secretProperty = 9;
alert(obj._secretProperty); // 9 - ...
alert(obj.getSecretProperty()); // 42 - , ! :-)
obj.setSecretProperty(78);
alert(obj.getSecretProperty()); // 78

* This source code was highlighted with Source Code Highlighter .

もちろん、すべては単純ですが。

ステップ3:よりJavaScriptの方法で


改善、改善。 getSomeProperty()/setSomeProperty(...)アプローチは面倒です。 もっと簡潔にできますが、同時にPCメモリを節約し、後でそれを使用する開発者の時間を節約できます。
function MyObject(newVal) {
var _secretProperty = newVal;

/**
* @param {Object} newVal - _secretProperty. .
* , secretProperty(...) , setter.
* , secretProperty() , getter.
*/
this .secretProperty = function (newVal) {
if ( typeof newVal != "undefined" )
_secretProperty = newVal;
return _secretProperty;
}
}

// :
var obj = new MyObject(42);
alert(obj._secretProperty); // undefined
alert(obj.secretProperty()); // 42
obj.secretProperty(78);
alert(obj.secretProperty()); // 78

* This source code was highlighted with Source Code Highlighter .

パラメーターがあり、次にセッターがあります。 パラメータなし-ゲッター。 主なことは、JSDocアノテーションでそれを記述することです:)
この方法では、すでに停止できます。 はい、彼は良いですが、私たちはさらに行きます!

レガシー構文


より興味深いオプションにシームレスに移行します。 これらの最初のものは、レガシー構文と呼ばれるものです。 これは、get / set(これについては後述します)などのJavaScript構文の構築がまだ実装されていないため、「まあまあ」でした。
var obj = {
real_a: 1
};

// , DOM, (, IE ) :
// __defineGetter__, __defineSetter__, __lookupGetter__, __lookupSetter__
// getter' setter':
obj.__defineGetter__( "a" , function () { return this .real_a * 2; });
obj.__defineSetter__( "a" , function (v) { return this .real_a = v / 2; });

// getter' setter':
alert(obj.__lookupGetter__( 'a' )) // some function-getter for 'a'
alert(obj.__lookupGetter__( 'b' )) // undefined
alert(obj.__lookupSetter__( 'a' )) // some function-setter for 'a'

//
alert(obj.real_a); // 1
obj.a = 9; // setter
alert(obj.real_a); // 4.5
alert(obj.a); // 9; getter

* This source code was highlighted with Source Code Highlighter .

このコードは次の場合に最適です
Icon: Firefox FF 1.0+、 Icon: Chrome Chrome 0.2以降、 Icon: Safari Safari 3.0以降、 Icon: Opera Opera 9.5以降
で動作しません:
Icon: IE IE-8.0を含むすべてのバージョン

はい、そしていくつかの興味深い機能があります( 重要! ):

例(コード内のコメントを参照):
var obj = {attr:5};
obj.__defineSetter__( 'attr' , function (val){
// :
// this.attr = val * 5
// .. setter.
// :
this .v = val * 5;
})
alert(obj.attr); // undefined. , getter/setter "" , .
// - - -.
// , setter 'attr', getter.
obj.attr = 3; // setter :)
alert(obj.v); // 15. setter .

* This source code was highlighted with Source Code Highlighter .


取得/設定


しかし、このアプローチはすでに「風水による」。 例を見ます:
var obj = {
real_a: 1,
get a() { return this .real_a * 2; },
set a(v) { return this .real_a = v / 2; }
};

//
alert(obj.real_a); // 1
obj.a = 9; // setter
alert(obj.real_a); // 4.5
alert(obj.a); // 9; getter

// __lookupGetter__/__lookupSetter__ - :
alert(obj.__lookupGetter__( 'a' )) // some function-getter for 'a'
// ..

* This source code was highlighted with Source Code Highlighter .

このコードは次の場合に最適です:
Icon: Firefox FF 1.0+、 Icon: Chrome Chrome 0.2以降、 Icon: Safari Safari 3.0以降、 Icon: Opera Opera 9.5以降
で動作しません:
Icon: IE IE-8.0を含むすべてのバージョン

前の例を(従来の構文から、上記を参照)繰り返しましたが、コードの量は何回減少しました! これは素晴らしいです(そう思われます)!
しかし、ありません。 get / set構造がサポートされていないブラウザでは、このコードにより構文エラーが発生します。 したがって、今のところ、私は使用を控えます(まあ、またはtry-catchに詰め込みますが、そうではありません)。

一般に、get / setを介した記録は、レガシー構文を介した記録と完全に類似しています。

Firefoxの方法


FFはゲッターとセッターでさらに進んで(ところで、理由はわかりません)、+ 2台の自転車を作成しました:)

1番:
var obj = {
get ab() { /**/ },
set ac(v) { /**/ }
};

alert(obj.__lookupGetter__( 'a' )) // function b()
alert(obj.__lookupSetter__( 'a' )) // function c(v)
// ..

* This source code was highlighted with Source Code Highlighter .

基本的に、 名前付きハンドラー関数を定義できます。 以上です。 なぜこれが必要なのか分かりません。

2番:
function magicGetter() { return 42; };

var obj = {
a getter: function b() { /**/ },
a setter: function (v) { /**/ },
'^_^' getter: magicGetter
};

alert(obj.__lookupGetter__( 'a' )) // function b()
alert(obj.__lookupSetter__( 'a' )) // function(v)
alert(obj.__lookupGetter__( '^_^' )) // function magicGetter()

alert(obj[ "^_^" ]); // 42

* This source code was highlighted with Source Code Highlighter .

このコードは、以下でのみ正常に機能ます。
Icon: Firefox FF 1.0+

ここでは、 名前付きハンドラー関数を指定することもできますが、前のハンドラー関数よりも2つの利点があります。 外部ハンドラー関数を定義し、 無効な文字(「。」による書き込み用)Charactersのゲッター/セッターを指定します

これはすべて__defineGetter __ / __ defineSetter__を使用して実行できます。 自転車だから。

はい、これら2つの方法のいずれかを使用すると、FFを除くすべての場所でSyntaxErrorが発生します。 覚えて! :)

IEの方法


Internet Explorerは、いつものように「私はあなたの道を進んでいない」と言い、ゲッターとセッターを独自の方法で作成しました。

IE 8.0+


バージョン8から始めましょう。 Object.defineProperty(...)メソッドはObject.defineProperty(...)に実装されていObject.defineProperty(...)が、 Object.defineProperty(...) 、DOM要素にのみ適用されます。
// IE 8.0
Object.defineProperty( document .body, "description" , {
get : function () {
alert( 'Getting description...' );
return this .desc;
},
set : function (val) {
alert( 'Setting description...' );
this .desc = val;
}
});
document .body.description = "Content container" ; // "Setting description..."
alert( document .body.description); // "Getting description..." -> "Content container"
alert( document .body.desc); // "Content container"

// DOM-:
var obj = {};
Object.defineProperty(obj, "prop" , {
get : function () { /**/ }
}); // JS ERROR: Object doesn't support this action. -. .

* This source code was highlighted with Source Code Highlighter .

ルールは引き続き有効です。a 同じ名前の属性が消去されます。 b) 1つのゲッターはセッターを自動的に追加しません(逆も同様です)。

それでもこのメカニズムを非DOM要素に適用したい場合は、オブジェクトをかわして、DOM要素で置き換える必要があります。

IE 5.0+


IE 8.0より前のバージョンでは、ゲッターとセッターのメカニズムは本質的にありません。 ただし、 onpropertychangeには素晴らしいイベントがonpropertychangeます。 DOM要素にのみ存在します。 これを使用して、セッターを作成できます。 しかし、私はゲッターのために何も見つけませんでした。 例:
document .body.onpropertychange = function () {
var pn = window. event .propertyName;
var pv = window. event .srcElement[window. event .propertyName];
if (pn == "description" )
alert(pv);
}
document .body.description = "Content container" ; // setter alert "Content container"
alert( document .body.description); // "Content container". getter. description

// DOM- onproperychange
var el = document .createElement( "DIV" );
el.onpropertychange = function () {
var pn = window. event .propertyName;
var pv = window. event .srcElement[window. event .propertyName];
if (pn == "description" )
alert(pv);
}
el.description = "Content container" ; // . , ...
// DOM-:
document .appendChild(el);
el.description = "Content container" ; // setter alert "Content container"

* This source code was highlighted with Source Code Highlighter .

以前のObject.definePropertyは違いがあります:

このアプローチは、IE 5.0( MSDNが述べているように )および現在の最新バージョンから機能します。 まあ、そしてすでにDOMにいる人だけのために。

結論、または今のところ


小さなクロスブラウザフレームワークを実装する機会を残します-あなた、仲間:)しかし、私はそれを作ることは本物だと言います。 IEにとっては簡単ではありませんが。

助けて


この記事では、これらまたはそれらのゲッターおよびセッターメカニズムが最も一般的なブラウザーで動作することを指摘しました。 しかし、これらはすべてのブラウザーとはほど遠いものです。 したがって、私は明確にします:
Icon: Firefox Firefox 0.9以降| エンジン: Gecko 1.7+ (JSエンジン:SpiderMonkey / TraceMonkey)
Icon: Chrome Chrome 0.2以降| エンジン: WebKit 522+ (JSエンジン:V8)
Icon: Safari Safari 3.0以降| エンジン: WebKit 522+ (JSエンジン:JavaScriptCore)
Icon: Opera Opera 9.5以降| エンジン: Presto 2.1+ (JSエンジン:Futhark)
Icon: IE IE 5.0-IE 7.0 | エンジン: トライデント(バージョン管理外) (JSエンジン:JScript 5.0-JScript 5.7)
Icon: IE IE 8.0+ | エンジン: Trident 4.0+(JSエンジン:JScript 5.8+)

Engine / JSエンジンをよく見てください。 ブラウザについて言及するのを忘れたが、リストされたエンジンの1つを使用している場合(エンジンのバージョンが重要です)、すべてが言及されたブラウザと同じように動作します。

ご清聴ありがとうございました。

Source: https://habr.com/ru/post/J66242/


All Articles