web-dev-qa-db-ja.com

プロトタイプでセッター/ゲッターを定義する方法

2016年10月編集:この質問は2012年に行われたものであることに注意してください。毎月、誰かが新しい回答またはコメントに反論するコメントを追加しますが、質問はおそらく古くなっているので、そうするのは本当に理にかなっています(覚えている、それはGnome Javascriptがブラウザではなくgnome-Shell拡張機能を書くためだったことを思い出してください非常に具体的なもの)。

Javascriptでサブクラス化を行う方法について 私の前の質問 に従って、スーパークラスのサブクラスを次のように作成しています。

function inherits(Child,Parent) {
    var Tmp = function {};
    Tmp.prototype = Parent.prototype;
    Child.prototype = new Tmp();
    Child.prototype.constructor = Child;
}
/* Define subclass */
function Subclass() {
    Superclass.apply(this,arguments);
    /* other initialisation */
}
/* Set up inheritance */
inherits(Subclass,Superclass);
/* Add other methods */
Subclass.prototype.method1 = function ... // and so on.

私の質問は、この構文でプロトタイプにセッター/ゲッターを定義するにはどうすればよいですか?

やったことある:

Subclass.prototype = {
    __proto__: Superclass.prototype,
    /* other methods here ... */

    get myProperty() {
        // code.
    }
}

しかし、明らかに以下は機能しません:

Subclass.prototype.get myProperty() { /* code */ }

私はGJS(GNOME Javascript)を使用していますが、エンジンはMozilla Spidermonkeyのエンジンとほぼ同じになるように設計されています。私のコードはブラウザ向けではありません。GJSでサポートされている限り(Spidermonkeyを意味するのでしょうか?)、クロス互換性がなくても構いません。

72

オブジェクトリテラル宣言の使用(最も簡単な方法):

var o = {
    a: 7,
    get b() {
        return this.a + 1;
    },
    set c(x) {
        this.a = x / 2
    }
};

Object.defineProperty の使用(ES5をサポートする最新のブラウザー):

Object.defineProperty(o, "myProperty", {
    get: function myProperty() {
        // code
    }
});

または__defineGetter____defineSetter__を使用して([〜#〜] deprecated [〜#〜]):

var d = Date.prototype;
d.__defineGetter__("year", function() { return this.getFullYear(); });
d.__defineSetter__("year", function(y) { this.setFullYear(y); });
66
bfavaretto

_Subclass.prototype_で Object.defineProperty() を使用します。一部のブラウザでは ___defineGetter___ および ___defineSetter___ も使用できますが、これらは非推奨です。たとえば、次のようになります。

_Object.defineProperty(Subclass.prototype, "myProperty", {
    get: function myProperty() {
        // code
    }
});
_
94
Bergi

私はあなたがこのようにしたかったと思う:

function Unit() {
        this._data; // just temp value
}
Unit.prototype = {
        get accreation() {
                return this._data;
        },
        set accreation(value) {
                this._data = value
        },
}
Unit.prototype.edit = function(data) {
        this.accreation = data; // setting
        this.out();
};

Unit.prototype.out = function() {
    alert(this.accreation); // getting
};

var unit = new Unit();
unit.edit('setting and getting');

function Field() {
    // children
}

Field.prototype = Object.create(Unit.prototype);

Field.prototype.add = function(data) {
  this.accreation = data; // setting
        this.out();
}

var field1 = new Field();
field1.add('new value for getter&setter');

var field2 = new Field();
field2.out();// because field2 object has no setting

「オブジェクトのプロトタイプの内部」でセッターとゲッターを定義するには、次のようにする必要があります。

Object.defineProperties(obj.__proto__, {"property_name": {get: getfn, set: setfn}})

ユーティリティ関数でそれを短縮できます:

//creates get/set properties inside an object's proto
function prop (propname, getfn, setfn) {
    var obj = {};
    obj[propname] = { get: getfn, set: setfn };
    Object.defineProperties(this, obj);        
}

function Product () {
     this.name =  "Product";
     this.amount =  10;
     this.price =  1;
     this.discount =  0;
}

//how to use prop function
prop.apply(Product.prototype, ["total", function(){ return this.amount * this.price}]);

pr = new Product();
console.log(pr.total);

ここでは、prop.applyを使用して、コンテキストProduct.prototypeを呼び出すときに「this」として設定します。

このコードを使用すると、質問では、インスタンスではなく、オブジェクトのプロトタイプ内のget/setプロパティで終了します。

(テスト済みのFirefox 42、Chrome 45)

5
Mackraken

Object.defineProperty()メソッドにより、コンストラクターでゲッターまたはセッターを指定します。このメソッドは3つの引数を取ります。最初の引数はプロパティを追加するオブジェクト、2番目はプロパティの名前、3番目はプロパティの記述子です。たとえば、次のようにpersonオブジェクトのコンストラクターを定義できます。

var Employee = (function() {
    function EmployeeConstructor() {
        this.first = "";
        this.last = "";
        Object.defineProperty(
            this,
            "fullName", {
                get: function() {
                    return this.first + " " +
                        this.last;
                },
                set: function(value) {
                    var parts = value.toString().split(" ");
                    this.name = parts[0] || "";
                    this.last = parts[1] || "";
                }
            });
    }
    return
    EmployeeConstructor;
}());

Object.defineProperty()を使用すると、プロパティ定義をより細かく制御できます。たとえば、記述しているプロパティを動的に削除または再定義できるかどうか、値を変更できるかどうかなどを指定できます。

記述子オブジェクトの次のプロパティを設定することにより、このような制約を設定できます。

  • 書き込み可能:これは、プロパティの値を変更できるかどうかを示すブール値です。デフォルト値はfalseです
  • 構成可能:これは、プロパティの記述子を変更できるか、プロパティ自体を削除できるかを示すブール値です。デフォルト値はfalseです
  • 列挙可能:これは、オブジェクトのプロパティのループでプロパティにアクセスできるかどうかを示すブール値です。デフォルト値はfalseです
  • 値:これは、プロパティに関連付けられた値を表します。デフォルト値は未定義です
4