如何在原型上定义setter / getter
编辑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.
我的问题是, 如何在这个语法的原型上定义一个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?),我不介意它是不是交叉兼容。
使用对象字面声明(最简单的方法):
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); });
在Subclass.prototype
上使用Object.defineProperty()
。 在一些浏览器上也有__defineGetter__
和__defineSetter__
,但是不推荐使用。 举个例子,这将是:
Object.defineProperty(Subclass.prototype, "myProperty", { get: function myProperty() { // code } });
我想你想这样做:
要在对象的原型中定义setter和getters,你必须这样做:
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属性,而不是实例。
(经过testing的Firefox 42,Chrome 45)
通过Object.defineProperty()方法在构造函数中指定一个getter或setter。 该方法有三个参数:第一个参数是要添加属性的对象,第二个参数是属性的名称,第三个参数是属性的描述符。 例如,我们可以定义我们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()可以更好地控制我们的属性定义。 例如,我们可以指定我们正在描述的属性是否可以dynamic删除或重新定义,如果它的值可以改变,依此类推。
我们可以通过设置描述符对象的以下属性来进行这种约束:
- 可写:这是一个布尔值,表示属性的值是否可以改变; 其默认值为false
- 可configuration:这是一个布尔值,表示属性的描述符是可以更改的还是属性本身可以被删除; 其默认值为false
- enumerable:这是一个布尔值,指示是否可以在对象的属性中循环访问该属性; 其默认值为false
- 价值:这表示与财产相关的价值; 其默认值是未定义的