29

コードで down のような動作を実現したい:

function Foo(name) {
    this.name = name;
};

var myFoo = new Foo('myName');

myFoo.name('newMyName'); // sets myFoo.name = 'newMyName'
myFoo.name(); // returns 'myName'

しかし、その場合、name プロパティを name 関数でオーバーライドしていることは明らかです。とにかくその機能を達成することは可能ですか?

4

2 に答える 2

43

JavaScript でゲッターとセッターについて話すとき、次の 2 つの概念のいずれかについて話している可能性があります。

1. 他の OO 言語のような概念としてのゲッターとセッター。

これは、質問のコードで示されているケースです。この場合、オブジェクトのプロパティは単純に、オブジェクトまたは関数のいずれかであるプロパティです。javascript は、同じ名前空間内で両方を追跡します。実際、JavaScript では関数は単なるオブジェクトであるため、C などの言語で見られるような、関数用の個別の名前空間という概念はありません。

この場合、「ゲッター」と「セッター」は単なる通常の関数であるため、値を個別に保存する必要があります。これにはいくつかの戦略があります。

1 つは、Java で一般的に見られる暗黙getSomething()のスタイル関数を使用することです。setSomething()これにより、getter と setter の名前に「get」と「set」という単語が追加されるため、プロパティ名から getter と setter を明確にすることができます。

2番目の戦略は、質問に書いたものです。この場合、getter/setter と同じ名前を共有しないように、プロパティを別の名前で保存する必要があります。

3 番目の戦略は、値をクロージャーに格納することです。

    function Foo (name) {
        var name = name;
        this.name = function (str) {
            if (str !== undefined) name = str;
            return name;
        }
    }

上記のコードでは値が格納されていますnameが、getter/setter はthis.nameまったく別の変数であることに注意してください。これにより、サンプル コードが期待どおりに動作するようになります。

    var me = new Foo('Mark');
    me.name(); // returns Mark
    me.name('Andy'); // sets name to Andy

2. javascript のメカニズムとしてのゲッターとセッター。

これは、ECMAscript 5 仕様に準拠した新しいバージョンの JavaScript の機能です。この機能を使用すると.innerHTML、DOM オブジェクトのプロパティに何かを割り当てたときに HTML パーサーを呼び出すのと同様に、読み取りまたは書き込み時にプロパティでコードを実行できます。

getter と setter の構文は関数に似ていますが、 の代わりにgetandsetキーワードが導入されていfunctionます。

getter と setter を使用したプロパティの簡単な例:

    var me = {
        first_name : "",
        last_name : "",
        get name() {
            return this.first_name + " " + this.last_name;
        },
        set name(str) {
            var n = str.split(/\s+/);
            this.first_name = n.shift();
            this.last_name = n.join(' ');
        }
    }

上記のコードを使用すると、first_nameandを取得および設定する関数をlast_name、関数ではなく変数であるかのように扱うことができます。ゲッターとセッターを使用するには、次のnameようにします。

    me.name = "James Bond";
    alert(me.first_name); // should alert James
    alert(me.last_name); // should alert Bond
    me.last_name = "Dean";
    alert(me.name); // should alert James Dean

JavaScript の get/set メカニズムを使用すると、同じ名前を使用してオブジェクトに値を格納することはできません。例えば:

    var foo = {
        set bar(x) {this.bar=x}
    }

上記のコードはコンパイルされますが、bar: を設定しようとするfoo.bar = 1と、無限ループのためにスタック オーバーフローが発生します -this.bar=セッター内でセッターが再度呼び出されます。

于 2013-10-23T05:35:10.967 に答える
0

プロパティと同じ名前の JavaScript getter/setter を使用する場合 (特定のセッターをインターセプトして副作用を実装する場合など) はProxy、オブジェクトの を作成できます。

function editableProxy (myObj) {
    return new Proxy(myObj, {
        toJSON: () => myObj,
        get: function (target, prop) {
            return Reflect.get(myObj, prop);
        },
        set: function (target, prop, receiver) {
            if (prop === 'billTo') {
                myObj.billToId = receiver?.id;
            }
            return Reflect.set(myObj, prop, receiver);
        },
    });
};

すべてのゲッターは正常に動作します。セッターは正常に動作しますが、a を設定するbillToと、billToId も設定されます。

let da = {id:123}
let wrapped = editableProxy(da)
let id = wrapped.id // 123
wrapped.id=234
wrapped.id===da.id // true
wrapped.billTo={id:567,name:'Big Bad Bill'} // triggers setter side effect
wrapped.billToId // 567
于 2021-09-15T17:05:18.000 に答える