Javascriptのゲッターとセッター

Javascriptは非常にエレガントな言語であり、多くの興味深い機能を備えています。 これらの機能のほとんどは、1つの不快な要素、つまりInternet Explorerなどの作業が必要ながらくたによって隠されています。 それにもかかわらず、最新のブラウザを備えた携帯電話と通常のエンジンを備えたサーバー側のJavaScriptの出現により、これらの機能は今すぐ使用できます。 ただし、node.js用にプログラミングする場合でも、IE6 +で動作するように作成するようにしています。

この記事では、エレガントでゲッターとセッターを指定し、Mootoolsのソースコードを少し掘り下げる、興味深く非秘密の方法について説明します。 この情報の一部は、John Resigの記事 (一部は私の個人的な経験と実験)から取られています
function Foo(bar){ this._bar = bar; } Foo.prototype = { get bar () { return this._bar; }, set bar (bar) { this._bar = bar; } }; 



標準ゲッター


ゲッターとセッターとは何ですか? 通常、クロスブラウザは次のようになります。
 function Foo(bar) { this._bar = bar; }; Foo.prototype = { setBar : function (bar) { this._bar = bar; }, getBar : function () { return this._bar; } }; var foo = new Foo; foo.setBar(123); alert(foo.getBar()); 


さらに進んで、よりエレガントなオプションを作成できます。
 function Foo(bar) { var _bar = bar; this.bar = function (bar) { if (arguments.length) _bar = bar; else return _bar; } }; var foo = new Foo; foo.bar(123); alert(foo.bar()); 


ネイティブのゲッター/セッター


しかし、すべてのサーバーエンジンと最新のブラウザー、つまりFirefox、Chrome、Safari3 +、Opera9.5 +で機能するより便利な方法があります。これは、プロパティをプロパティとして参照し続けるようにプロパティのセッターとゲッターを設定します。 このアプローチにはいくつかの利点があります。
1.よりエレガントなレコード。 ORMを想像してください:
 for (var i in topics.comments); // vs for (var i in topics.loadComments()); 

2.プロパティに基づくAPIが既に存在し、変更できない場合(ただし、非常に必要です)。

そのようなゲッター/セッターを設定するには、2つの方法があります。

オブジェクト経由:


 function Foo(bar) { this._bar = bar; }; Foo.prototype = { set bar (bar) { this._bar = bar; }, get bar () { return this._bar; } }; var foo = new Foo; foo.bar = 123; alert(foo.bar); 


__defineGetter__および__defineSetter__メソッド経由:


 function Foo(bar) { var _bar = bar; this.__defineGetter__("bar", function(){ return _bar; }); this.__defineSetter__("bar", function(val){ _bar = bar; }); }; var foo = new Foo; foo.bar = 123; alert(foo.bar); 


ブラウザーサポートの定義


これから、ブラウザがゲッターをサポートしているかどうかを判断する簡単な方法を取得できます。
 return (typeof {}.__defineGetter__ == 'function'); 


継承をどうしますか?


.__lookupGetter__および.__lookupSetter__ 、getterまたはsetter関数自体を取得でき.__lookupSetter__
 function extend(target, source) { for ( var prop in source ) { var getter = source.__lookupGetter__(prop), setter = source.__lookupSetter__(prop); if ( getter || setter ) { if ( getter ) target.__defineGetter__(prop, getter); if ( setter ) target.__defineSetter__(prop, setter); } else a[i] = b[i]; } return target; } 

したがって、親ソースのターゲット値がターゲットに渡されるのではなく、ゲッター/セッター関数が渡されます。

覚えておくべきこと


John Resigからのコメント:
*プロパティごとに、1つのゲッターおよび/またはセッターのみを設定できます。 2つのゲッターまたはセッターは存在できません
*ゲッターまたはセッターを削除する唯一の方法は、 delete object[name];を呼び出すことdelete object[name]; 。 このコマンドは、getterとsetterの両方を削除します。あるものを削除して他のものを残したい場合は、まずそれを保存し、削除後に再度割り当てる必要があるためです。
* __defineGetter__または__defineSetter__を使用すると、直前のgetterまたはsetterが静かに上書きされ、その名前のプロパティも削除されます。
*ブラウザーが単純なスニペットを使用してゲッターとセッターをサポートしているかどうかを確認します。
 javascript:foo={get test(){ return "foo"; }};alert(foo.test); 



MooTools


Mutulsはデフォルトでこの機能をサポートしていません。 そして、 すでにパッチを提案していますが、ゲッターとセッターを理解させるために(ソースを少し変更するだけで)簡単にできます。
それで、私たちの目標は何ですか?
 var Foo = new Class({ set test : function () { console.log('test is set'); }, get test : function () { console.log('test is got'); return 'test'; }, }); foo.test = 1234; // test is set alert(foo.test); // test is get 

さらに、親クラスのゲッターとセッターは、ImplementsおよびExtendsを介して継承されたクラスでも機能する必要があります。 すべてのアクションは、匿名関数内のファイル[名前:クラス]で発生します。
最初に、関数の最上部で、ゲッターとセッターのみを上書きする関数を定義します。 そして、私たちは時代遅れのブラウザを捨てましたが、それは保証する価値があります。
 var implementGettersSetters = (typeof {}.__lookupGetter__ == 'function') ? function (target, source) { for (var key in source) { var g = source.__lookupGetter__(key), s = source.__lookupSetter__(key); if ( g || s ) { if (g) target.__defineGetter__(key, g); if (s) target.__defineSetter__(key, s); } } return target; } : function (target, source) { return target; }; 


もちろん、このようなゲッターを使用したスクリプトが古いブラウザーにアクセスすると、クラッシュするだけですが、これは誰かが誤ってこのファイルを取得してサイトにフックするのを防ぐための保険であり、ロバに何があるのか​​疑問に思いました。
__lookupGetter__がサポートされていない場合、関数は何も実行しないことがわかります。

これで、クラスの作成および継承(拡張)中にgetterおよびsetterが機能するようになりました。 これを行うには:
 //  var Class = this.Class = new Type('Class', function(params){ //   newClass.$constructor = Class; newClass.prototype.$constructor = newClass; newClass.prototype.parent = parent; //   ,    (, ,   !)  : implementGettersSetters(newClass.prototype, params); 


別の動きは、不純物(実装)からのゲッターとセッターの継承を実装することです。 これを行うには、組み込みのMutatorsを見つけて、1行だけ追加します。
 Class.Mutators = { // ... Implements: function(items){ Array.from(items).each(function(item){ var instance = new item; for (var key in instance) implement.call(this, key, instance[key], true); //  : implementGettersSetters(this.prototype, instance); }, this); } }; 


セッターとゲッターが実装され、それらを簡単に継承して使用できるようになりました。 お楽しみください)

 var Foo = new Class({ initialize : function (name) { this.name = name; }, set test : function () { console.log(this.name + ' test is set'); }, get test : function () { console.log(this.name + ' test is got'); return 'test'; }, }); var Bar = new Class({ Extends : Foo }); var Qux = new Class({ Implements : [ Foo ] }); var foo = new Foo('foo'); foo.test = 1234; // foo test is set alert(foo.test); // foo test is got var bar = new Bar('bar'); bar.test = 1234; // bar test is set alert(bar.test); // bar test is got var qux = new Qux('qux'); qux.test = 1234; // qux test is set alert(qux.test); // qux test is got 


興味深いリンク:


Object.defineProperty書き込み可能、​​取得、設定、構成可能、列挙可能など、非常に幅広い設定でプロパティを作成するためのツール
Object.create必要なオブジェクトをすばやく作成できます。

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


All Articles