如何在原型上定义setter / getter

时间:2012-05-15 00:29:15

标签: javascript getter

2016年10月编辑:请注意这个问题是在2012年提出的。每个月都会有人添加一个新的答案或评论来反驳答案,但这样做并没有多大意义。这个问题可能已经过时了(记住,这是用于 Gnome Javascript 来编写gnome-shell扩展,而不是浏览器的东西,这是非常具体的。)

关于如何在Javascript中进行子类化的my previous question之后,我正在创建一个超类的子类,如下所示:

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.

我的问题是,如何使用此语法在原型上定义setter / getter?

我以前做过:

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

    get myProperty() {
        // code.
    }
}

但显然以下方法不起作用:

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

我正在使用GJS(GNOME Javascript),并且该引擎与Mozilla Spidermonkey一致或多或少相同。我的代码不适用于浏览器,只要它受GJS支持(我猜这意味着Spidermonkey?),我不介意它是否不是交叉兼容的。

6 个答案:

答案 0 :(得分:91)

Subclass.prototype上使用Object.defineProperty()。某些浏览器还提供__defineGetter____defineSetter__,但不推荐使用它们。对于您的示例,它将是:

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

答案 1 :(得分:65)

使用对象文字声明(最简单的方法):

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); });

答案 2 :(得分:32)

我想你想这样做:

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

答案 3 :(得分:4)

要在“对象的原型”中定义setter和getter,你必须做这样的事情:

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)

答案 4 :(得分:3)

通过Object.defineProperty()方法在构造函数中指定getter或setter。 这个方法有三个参数:第一个 参数是要添加属性的对象,第二个是属性的名称,和 第三个是属性的描述符。例如,我们可以为我们定义构造函数 人物如下:

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()给出 更多地控制我们的属性定义。例如,我们可以指定我们的属性 可以动态删除或重新定义描述,如果其值可以更改,等等 上。

我们可以通过设置描述符对象的以下属性来实现这些约束:

  • writable:这是一个布尔值,表示是否为值 财产可以改变;其默认值为false
  • configurable:这是一个布尔值,表示属性是否属性 描述符可以更改或属性本身可以删除;它的 默认值为false
  • enumerable:这是一个布尔值,指示属性是否可以 在对象属性的循环中访问;它的默认值是 假
  • value:表示与该属性关联的值;它的 默认值未定义

答案 5 :(得分:0)

这是Animal → Dog继承的简单示例,其中Animal具有 getter setter

//////////////////////////////////////////
// General Animal constructor
function Animal({age, name}) {
  // if-statements prevent triggering the setter on initialization
  if(name) this.name = name
  if(age) this.age = age
}

// an alias "age" must be used, so the setter & getter can use an
// alternative variable, to avoid using "this.age", which will cause
// a stack overflow of "infinite" call stack when setting the value.
Object.defineProperty(Animal.prototype, "age", {
  get(){
    console.log("Get age:", this.name, this._age) // getting
    return this._age
  },
  set(value){
    this._age = value
    console.log("Set age:", this.name, this._age) // setting
  }
})




//////////////////////////////////////////
// Specific Animal (Dog) constructor
function Dog({age = 0, name = 'dog'}) {
  this.name = name
  this.age = age
}

// first, defined inheritance
Dog.prototype = new Animal({});

// add whatever additional methods to the prototype of Dog
Object.assign(Dog.prototype, {
  bark(woff){
    console.log(woff)
  }
})


//////////////////////////////////////////
// Instanciating
var koko = new Animal({age:300, name:'koko'})
var dog1 = new Dog({age:1, name:'blacky'})
var dog2 = new Dog({age:5, name:'shorty'})

console.log(dog1)
koko.age
dog1.age = 3;
dog1.age
dog2.age