ダミーのゲッター\セッター


133

私はゲッターとセッターの周りに頭を近づけようとしましたが、沈みません。JavaScriptのゲッターとセッター、およびゲッターとセッターの定義を読んだだけで、理解できません。

誰かが明確に述べることができます:

  1. ゲッターとセッターが何をするためのものか、そして
  2. 非常に簡単な例を挙げてください。

12
個人的には、ジョンの説明よりも明確な説明を得る方法がわかりません...
Jason Bunting

オブジェクト指向の世界では、ゲッターとセッターが適切にカプセル化されたクラスの作成を支援します
オーバーエクスチェンジ'29年

基本的には次のように表示されます。プロパティを取得および設定するためのオーバーロードを定義していて、これらのオーバーロードは関数です。しかし、あなたはそれらを呼び出す必要はありません。この方法は、あなたは置き換えることができますa = setValue(5);a = 5;し、setValue()それによって、あなたが好きなものは何でもするためにボンネットの下に呼び出されます。
Andrew

回答:


102

@millimooseの回答に加えて、セッターを使用して他の値を更新することもできます。

function Name(first, last) {
    this.first = first;
    this.last = last;
}

Name.prototype = {
    get fullName() {
        return this.first + " " + this.last;
    },

    set fullName(name) {
        var names = name.split(" ");
        this.first = names[0];
        this.last = names[1];
    }
};

さて、あなたは設定することができfullName、かつfirstおよびlast更新され、その逆されます。

n = new Name('Claude', 'Monet')
n.first # "Claude"
n.last # "Monet"
n.fullName # "Claude Monet"
n.fullName = "Gustav Klimt"
n.first # "Gustav"
n.last # "Klimt"

2
@Akash:いいえ、ただし、Internet Explorer 9はObject.definePropertyゲッターとセッターを定義できる新しい関数をサポートしています。
Matthew Crumley、2011年

9
ありえないMSが正しくJSをサポートしていないと私は二回のプログラムのすべて、SL用と世界の残りの1 :)に持っているので、彼らは、どこでも自分のSilverlightの実行をしないこと、それは本当に痛い
Akashさんカバ

2
@Martin:Johnの回答と同じテクニックを使用して、プライベートにすることができます。実際のゲッター/セッターを使用したい場合は、this.__defineGetter__またはより新しいObject.defineProperty関数を使用する必要があります。
Matthew Crumley、2011

1
上記のアプローチの問題は1つだけです。既存のクラスのゲッターとセッターを追加したい場合、プロトタイプがオーバーライドされ、元のメソッドにアクセスできなくなります。
xchg.ca

1
このアプローチは上書きしませんName.prototype.constructorか?millimooseのAnswerの悪い代替案のようです。
r0estir0bbe

62

JavaScriptでのゲッターとセッター

概観

JavaScriptのゲッターとセッターは、計算されたプロパティまたはアクセサーの定義に使用されます。計算されたプロパティは、関数を使用してオブジェクト値を取得または設定するプロパティです。基本的な理論は次のようなことをしています:

var user = { /* ... object with getters and setters ... */ };
user.phone = '+1 (123) 456-7890'; // updates a database
console.log( user.areaCode ); // displays '123'
console.log( user.area ); // displays 'Anytown, USA'

これは、プロパティへのアクセス時に、数値が範囲内に留まる、文字列を再フォーマットする、値が変更されたイベントをトリガーする、リレーショナルデータを更新する、プライベートプロパティへのアクセスを提供するなど、舞台裏で自動的に行うのに役立ちます。

以下の例は基本的な構文を示していますが、特別なことをせずに内部オブジェクト値を取得および設定するだけです。上記のように、実際のケースでは、必要に応じて入力値または出力値、あるいはその両方を変更します。

キーワードの取得/設定

ECMAScript 5はgetset計算されたプロパティを定義するためのとキーワードをサポートしています。IE 8以下を除くすべての最新ブラウザーで動作します。

var foo = {
    bar : 123,
    get bar(){ return bar; },
    set bar( value ){ this.bar = value; }
};
foo.bar = 456;
var gaz = foo.bar;

カスタムゲッターとセッター

getおよびsetは予約語ではないため、オーバーロードして独自のカスタムブラウザー間計算プロパティ関数を作成できます。これはどのブラウザでも機能します。

var foo = {
    _bar : 123,
    get : function( name ){ return this[ '_' + name ]; },
    set : function( name, value ){ this[ '_' + name ] = value; }
};
foo.set( 'bar', 456 );
var gaz = foo.get( 'bar' );

または、よりコンパクトなアプローチでは、単一の関数を使用できます。

var foo = {
    _bar : 123,
    value : function( name /*, value */ ){
        if( arguments.length < 2 ){ return this[ '_' + name ]; }
        this[ '_' + name ] = value;
    }
};
foo.value( 'bar', 456 );
var gaz = foo.value( 'bar' );

このようなことはコードの肥大化につながる可能性があるため、避けてください。

var foo = {
    _a : 123, _b : 456, _c : 789,
    getA : function(){ return this._a; },
    getB : ..., getC : ..., setA : ..., setB : ..., setC : ...
};

上記の例については、内部プロパティ名は、単にやってからユーザーを阻止するために、アンダースコアで抽象化されているfoo.bar対をfoo.get( 'bar' )して「生」の値を取得します。条件付きコードを使用して、(nameパラメーターを介して)アクセスされているプロパティの名前に応じてさまざまなことを実行できます。

Object.defineProperty()

使用Object.defineProperty()はゲッターとセッターを追加するもう1つの方法であり、定義後にオブジェクトで使用できます。また、構成可能で列挙可能な動作を設定するためにも使用できます。この構文はIE 8でも機能しますが、残念ながらDOMオブジェクトでのみ機能します。

var foo = { _bar : 123 };
Object.defineProperty( foo, 'bar', {
    get : function(){ return this._bar; },
    set : function( value ){ this._bar = value; }
} );
foo.bar = 456;
var gaz = foo.bar;

__defineGetter __()

最後に、__defineGetter__()別のオプションです。これは非推奨ですが、Webで広く使用されているため、すぐになくなることはほとんどありません。IE 10以下を除くすべてのブラウザで動作します。他のオプションもIE以外でうまく機能するので、これはそれほど有用ではありません。

var foo = { _bar : 123; }
foo.__defineGetter__( 'bar', function(){ return this._bar; } );
foo.__defineSetter__( 'bar', function( value ){ this._bar = value; } );

また、注目に値する後者の例では、内部名は(すなわち、回避再帰へのアクセサ名とは異なるなければならないことであるfoo.bar呼び出すfoo.get(bar)呼び出しfoo.barを呼び出しますfoo.get(bar)...)。

こちらもご覧ください

MDN getsetObject.defineProperty()__ defineGetter __()__ defineSetter __()
MSDN IE8 Getter Support


1
よりコンパクトなアプローチthis[ '_' + name ] = value;かもしれないthis[ '_' + name ] = arguments[1];と指定する必要はないだろうvalueargが。
Redhart 2016

1
例: var foo = { bar : 123, get bar(){ return bar; }, set bar( value ){ this.bar = value; } }; foo.bar = 456; 例外を発生させます:Uncaught RangeError:最大コールスタックサイズがObject.setバーで[バーとして](<anonymous>:4:32)Object.setバーで[バーとして](<anonymous>:4:32) )at Object.set bar [as bar](<anonymous>:4:32)at Object.set bar [as bar](<anonymous>:4:32)at Object.set bar [as bar](<anonymous> :4:32)at Object.set bar [as bar](<anonymous>:4:32)
nevf

1
セット/取得名は、プロパティ名とは異なる必要があります。の代わりにbar: 123this.bar = valueなどをこれらに変更してください_bar 。参照:hongkiat.com/blog/getters-setters-javascript
nevf

@nevf訂正ありがとうございます!はい、一般的に計算された特性を持つ「本物の」内部1は次のように命名されます_foomFoo。ゲッター/セッターと同じ場合、再帰による無限ループが発生し、次にStack Overflow™;-)が発生します。 、これはa.get(b)を呼び出します...
Beejor

58

たとえば、これらを使用して、計算されたプロパティを実装します。

例えば:

function Circle(radius) {
    this.radius = radius;
}

Object.defineProperty(Circle.prototype, 'circumference', {
    get: function() { return 2*Math.PI*this.radius; }
});

Object.defineProperty(Circle.prototype, 'area', {
    get: function() { return Math.PI*this.radius*this.radius; }
});

c = new Circle(10);
console.log(c.area); // Should output 314.159
console.log(c.circumference); // Should output 62.832

(CodePen)


わかりました。取得し始めていると思います。配列オブジェクトのlengthプロパティにゲッターを割り当てようとしていますが、「var lengthの再宣言」というエラーが発生します。コードは次のようになります。obj = []; obj .__ defineGetter __( 'length'、function(){return this.length;});

1
これは、Arrayオブジェクトに組み込みの長さプロパティが既にあるためです。再宣言が許可された場合、新しい長さを呼び出すと無限に再帰します。プロパティ「my_length」などを呼び出してみてください。
ミリムース2009年

1つのステートメントで両方のゲッターを定義するには、を使用しますObject.defineProperties
r0estir0bbe

{"area":function(){return ...}}を作成できませんか?それをオブジェクトプロパティとして単に割り当てる
RegarBoy

@developerこれは、言語で定義されているJavaScriptのゲッターではなく、単なる関数です。値を取得するには、それを呼び出す必要があります。プロパティへのアクセスが過負荷になることはありません。また、JSがすでに持っているものを基に構築するのではなく、JSで独自の壊れたオブジェクトシステムを発明する人々のために用意された特別な地獄の輪があります。
ミリムース2018

16

古い質問を復活させて申し訳ありませんが、私はいくつかの非常に基本的な例と一般向けの説明を提供すると思います。これまでに投稿された他の回答はどれも、MDNガイドの最初の例のような構文を示していません。

ゲッター:

var settings = {
    firstname: 'John',
    lastname: 'Smith',
    get fullname() { return this.firstname + ' ' + this.lastname; }
};

console.log(settings.fullname);

...はJohn Smithもちろん記録されます。ゲッター変数オブジェクトのプロパティのように動作しますが、その場でその戻り値を計算する機能の柔軟性を提供します。これは基本的に、呼び出し時に()を必要としない関数を作成するための洗練された方法です。

セッター:

var address = {
    set raw(what) {
        var loc = what.split(/\s*;\s*/),
        area = loc[1].split(/,?\s+(\w{2})\s+(?=\d{5})/);

        this.street = loc[0];
        this.city = area[0];
        this.state = area[1];
        this.zip = area[2];
    }
};

address.raw = '123 Lexington Ave; New York NY  10001';
console.log(address.city);

... New Yorkコンソールに記録します。getterと同様に、setterはオブジェクトプロパティの値を設定するのと同じ構文で呼び出されますが、()なしで関数を呼び出すもう1つの豪華な方法です。

より徹底的で、おそらくより実用的な例については、このjsfiddleを参照してください。オブジェクトのセッターに値を渡すと、他のオブジェクトアイテムの作成または生成がトリガーされます。具体的には、jsfiddleの例では、数値の配列を渡すと、セッターが平均値、中央値、モード、および範囲を計算するように求められます。次に、各結果のオブジェクトプロパティを設定します。


getMethodまたはsetMethodを作成する場合と比較して、getおよびsetを使用する場合の利点がまだわかりません。()なしで呼び出すことができる唯一の利点はありますか?JavaScriptに追加される別の理由が必要です。
Andreas

@Andreasゲッターとセッターは、呼び出されたときにプロパティのように動作します。これは、意図された目的を明確にするのに役立ちます。彼らはそれ以外の場合は欠けている能力のロックを解除しませんが、それらの使用はあなたの思考を整理するのに役立ちます。それが本当のメリットです。実用的な例として、私はゲッターを使用してGoogle Mapsオブジェクトを拡張していました。マップタイルを地平線に対して平らに回転できるように、カメラのロール角度を計算する必要がありました。Googleは現在、これをバックエンドで自動的に行います。しかし、当時maps.rollは、maps.roll()戻り値ではなくプロパティとして取得することが役に立ちました。それは単なる好みです。
rojo 2016年

したがって、()なしでコードをきれいに見せるのは、単なる構文上の砂糖です。なぜあなたがあなたの例を使えなかったのか分かりませんmaps.roll()
Andreas

@Andreas誰が私ができなかったと言いますか?私が言うように、それは私が私の考えを整理しておくのを助けるための方法にすぎません。コーディングは芸術です。ボブ・ロスに、オレンジを使うことができたのに焦げた黄土色を使わなければならなかった理由を尋ねないでください。今は必要がないかもしれませんが、ある日あなたの絵が少し焦げた黄土が必要だと決心したとき、それはあなたのパレットにあります。
rojo 2016年

:) get構文とset構文が行うことの1つは、それがプロパティのプロパティとして使用されている場合に自動実行されることです。
Andreas

11

ゲッターとセッターは、クラスのプライベートプロパティがある場合にのみ意味があります。Javascriptには、通常オブジェクト指向言語で考えるようなプライベートクラスプロパティがないため、理解しにくい場合があります。次に、プライベートカウンターオブジェクトの例を示します。このオブジェクトの良い点は、内部変数「count」にオブジェクトの外部からアクセスできないことです。

var counter = function() {
    var count = 0;

    this.inc = function() {
        count++;
    };

    this.getCount = function() {
        return count;
    };
};

var i = new Counter();
i.inc();
i.inc();
// writes "2" to the document
document.write( i.getCount());

それでも混乱している場合は、JavaScriptのプライベートメンバーに関するクロックフォードの記事をご覧ください。


39
同意しません。ゲッターとセッターは、定義が単純な変数ではない可能性のある情報をカプセル化する場合にも非常に役立ちます。以前に単純なプロパティを使用していて、他のものが依存している可能性があるシステムの動作を変更する必要がある場合に便利です。さらに、この例では、単なる関数である「疑似ゲッター」のみを示しています。実際のJavaScriptゲッターは単純な値として表示され(そして関数表記なしでアクセスされます)、したがって、それらの真の力です。
devios1 2011年

私がそれを強力なものと呼ぶかどうかわかりません。何かが現れ XとしてではなくYは必ずしも明確ではない、本当にあります。私はvar baz = foo.barその背後に隠された振る舞いの完全なセットがあるとは絶対に期待しません。しかし、私はそれを期待していfoo.getBar()ます。
AgmLauncher

8

あなたがリンクする最初の記事はそれをかなり明確に述べていると思います:

この方法でJavaScriptを記述することの明らかな利点は、ユーザーが直接アクセスすることを望まないあいまいな値を使用できることです。

ここでの目標は、get()またはset()メソッドを介してフィールドへのアクセスのみを許可することにより、フィールドをカプセル化して抽象化することです。このようにして、フィールド/データを任意の方法で内部に格納できますが、外部コンポーネントは公開されたインターフェースから離れているだけです。これにより、外部インターフェイスを変更せずに内部の変更を加えたり、set()メソッド内で検証やエラーチェックを行ったりできます。


6

アクセス制御のないパブリックプロパティを持つオブジェクトの表示に慣れていることがよくありますが、JavaScriptを使用すると、プロパティを正確に記述することができます。実際、プロパティへのアクセス方法とそれに適用できるロジックを制御するために、記述子を使用できます。次の例について考えてみます。

var employee = {
    first: "Boris",
    last: "Sergeev",
    get fullName() {
        return this.first + " " + this.last;
    },
    set fullName(value) {
        var parts = value.toString().split(" ");
        this.first = parts[0] || "";
        this.last = parts[1] || "";
    },
    email: "boris.sergeev@example.com"
};

最終結果:

console.log(employee.fullName); //Boris Sergeev
employee.fullName = "Alex Makarenko";

console.log(employee.first);//Alex
console.log(employee.last);//Makarenko
console.log(employee.fullName);//Alex Makarenko

2

何がそんなに紛らわしいのですか?getterは、プロパティを取得するときに呼び出される関数であり、設定するときに設定します。たとえば、

obj.prop = "abc";

プロパティプロップを設定しています。ゲッター/セッターを使用している場合は、「abc」を引数として、セッター関数が呼び出されます。オブジェクト内のセッター関数の定義は、理想的には次のようになります。

set prop(var) {
   // do stuff with var...
}

それがどのようにブラウザ全体に実装されているのかはわかりません。Firefoxにも、二重下線付きの特別な(「マジック」)メソッドを使用した代替構文があるようです。いつものように、Internet Explorerはこれをサポートしていません。


2

コンストラクタのプロトタイプを介して、jsクラスのインスタンスメソッドを定義できます。

次にサンプルコードを示します。

// BaseClass

var BaseClass = function(name) {
    // instance property
    this.name = name;
};

// instance method
BaseClass.prototype.getName = function() {
    return this.name;
};
BaseClass.prototype.setName = function(name) {
    return this.name = name;
};


// test - start
function test() {
    var b1 = new BaseClass("b1");
    var b2 = new BaseClass("b2");
    console.log(b1.getName());
    console.log(b2.getName());

    b1.setName("b1_new");
    console.log(b1.getName());
    console.log(b2.getName());
}

test();
// test - end

そして、これはどのブラウザでも動作するはずです。nodejsを使用してこのコードを実行することもできます。


1
これは、新しいgetNameメソッドとsetNameメソッドを作成するだけです。これらはプロパティの作成とは関係ありません!
uzay95 2017年

2

私が読んだ説明にも少し戸惑いました。自分で記述していない既存のプロトタイプにプロパティを追加しようとしていたため、プロトタイプを置き換えるのは間違ったアプローチのようでした。だから、後世のために、ここに私がlastプロパティを追加した方法がありますArray

Object.defineProperty(Array.prototype, "last", {
    get: function() { return this[this.length - 1] }
});

関数IMHOを追加するよりも、少しだけ優れています。


1

アクセサーの概念を参照している場合、単純な目標は、基礎となるストレージを任意の操作から隠すことです。このための最も極端なメカニズムは

function Foo(someValue) {
    this.getValue = function() { return someValue; }
    return this;
}

var myFoo = new Foo(5);
/* We can read someValue through getValue(), but there is no mechanism
 * to modify it -- hurrah, we have achieved encapsulation!
 */
myFoo.getValue();

たとえば、実際のJSゲッター/セッター機能を参照している場合。defineGetter/ defineSetter、または{ get Foo() { /* code */ } }、それから、ほとんどの最新のエンジンでは、それらのプロパティのその後の使用は、それ以外の場合よりもはるかに遅くなることに注意する価値があります。例えば。のパフォーマンスを比較する

var a = { getValue: function(){ return 5; }; }
for (var i = 0; i < 100000; i++)
    a.getValue();

var a = { get value(){ return 5; }; }
for (var i = 0; i < 100000; i++)
    a.value;

-1

少し醜いかもしれませんが、プラットフォーム間でうまくいきます。

function myFunc () {

var _myAttribute = "default";

this.myAttribute = function() {
    if (arguments.length > 0) _myAttribute = arguments[0];
    return _myAttribute;
}
}

このように、あなたが呼び出すとき

var test = new myFunc();
test.myAttribute(); //-> "default"
test.myAttribute("ok"); //-> "ok"
test.myAttribute(); //-> "ok"

あなたが本当に物事にスパイスをかけたいなら、あなたはtypeofチェックを挿入することができます:

if (arguments.length > 0 && typeof arguments[0] == "boolean") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "number") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "string") _myAttribute = arguments[0];

または、高度なtypeofチェックでさらにクレイジーになりますcodingforums.comのtype.of()コード


重要なのは、パブリックインターフェイスを変更する必要なく、属性をより洗練されたものに変更できることでした。call()タグを追加すると変更されます。
マイケルスコットカスバート2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.