pim*_*vdb 31 javascript constructor prototype getter-setter
我最近读到了一个事实,即有可能在JavaScript中定义getter/setter.它似乎非常有用 - setter是一种'helper',可以在实际设置之前解析要设置的值.
例如,我目前有这个代码:
var obj = function(value) {
var test = !!value; // 'test' has to be a boolean
return {
get test() { return test },
set test(value) { test = !!value }
};
};
var instance = new obj(true);
Run Code Online (Sandbox Code Playgroud)
此代码始终转换value为布尔值.所以,如果你编码instance.test = 0,那么instance.test === false.
但是,要使其工作,您必须实际返回一个对象,这意味着新实例不是类型,obj而只是一个普通对象.这意味着更改原型obj对实例没有影响.例如,这并没有工作- instance.func是不确定的:
obj.prototype.func = function() { console.log(this.value); };
Run Code Online (Sandbox Code Playgroud)
因为instance不是类型obj.为了使原型函数工作,我想我不应该返回一个普通的对象,而是不返回任何东西,instance只有类型obj,就像常规构造函数一样.
那么问题是如何实现getter/setter?我只能找到描述如何将这些添加到对象的文章,而不是作为自定义类型的构造函数的一部分.
那么如何在构造函数中实现getter/setter,以便能够使用getter/setter并扩展原型?
Ray*_*nos 47
你不能这样做.
您可以为对象的属性设置setter/getters.我建议你使用ES5 Object.defineProperties.当然这仅适用于现代浏览器.
var obj = function() {
...
Object.defineProperties(this, {
"test": {
"get": function() { ... },
"set": function() { ... }
}
});
}
obj.prototype.func = function() { ... }
var o = new obj;
o.test;
o.func();
Run Code Online (Sandbox Code Playgroud)
IAM*_*L_X 10
通常你想要类方法.@Raynos在2011年5月7日的回答完成了工作,但是它定义了一个实例方法,而不是一个类方法.
下面说明了一个类定义,其中getter和setter是该类的一部分.这个定义很像@Raynos的答案,但代码中有两个不同之处:(1)"defineProperties()"动作已经移出构造函数.(2)"defineProperties()"的参数已从实例对象"this"更改为构造函数的原型对象.
function TheConstructor(side) {
this.side = side;
}
Object.defineProperties(TheConstructor.prototype, {
area: {
get: function() { return this.side * this.side; }
,set: function(val) { this.side = Math.sqrt(val); }
}
});
// Test code:
var anInstance = new TheConstructor(2);
console.log("initial Area:"+anInstance.area);
anInstance.area = 9;
console.log("modified Area:"+anInstance.area);
Run Code Online (Sandbox Code Playgroud)
产生这些结果:
initial Area:4
modified Area:9
Run Code Online (Sandbox Code Playgroud)
虽然通常类和实例定义之间的区别仅仅是一种风格问题,但是有一种良好风格的目的,并且存在区分重要的情况:记忆的吸气剂.这里描述了一个memoized getter的目的:智能/自我覆盖/懒惰的getter
当memoized值与整个类相关时,在类级别定义getter.例如,配置文件应该只读一次; 然后,结果值应适用于程序的持续时间.以下示例代码在类级别定义了memoized getter.
function configureMe() {
return 42;
}
Object.defineProperties(TheConstructor.prototype, {
memoizedConfigParam: {
get: function() {
delete TheConstructor.prototype.memoizedConfigParam;
return TheConstructor.prototype.memoizedConfigParam = configureMe();
}
,configurable: true
}
});
// Test code:
console.log("memoizedConfigParam:"+anInstance.memoizedConfigParam);
Run Code Online (Sandbox Code Playgroud)
生产:
memoizedConfigParam:42
Run Code Online (Sandbox Code Playgroud)
从示例中可以看出,memoized getter具有getter函数删除自身的特性,然后用一个简单的值替换它自己(可能)永远不会改变.请注意,'configurable'必须设置为'true'.
当memoized值取决于实例的内容时,在实例级别定义getter.定义在构造函数内部移动,关注对象是"this".
function TheConstructorI(side) {
this.side = side;
Object.defineProperties(this, {
memoizedCalculation: {
get: function() {
delete this.memoizedCalculation;
return this.memoizedCalculation = this.expensiveOperation();
}
,configurable: true
}
});
}
TheConstructorI.prototype.expensiveOperation = function() {
return this.side * this.side * this.side;
}
//Test code:
var instance2 = new TheConstructorI(2);
var instance3 = new TheConstructorI(3);
console.log("memoizedCalculation 2:"+instance2.memoizedCalculation);
console.log("memoizedCalculation 3:"+instance3.memoizedCalculation);
Run Code Online (Sandbox Code Playgroud)
生产:
memoizedCalculation 2:8
memoizedCalculation 3:27
Run Code Online (Sandbox Code Playgroud)
如果您想保证(而不是假设)永远不会更改memoized值,则需要更改'writable'属性.这使得代码更复杂一些.
function TheConstructorJ(side) {
this.side = side;
Object.defineProperties(this, {
memoizedCalculation: {
get: function() {
delete this.memoizedCalculation;
Object.defineProperty( this, 'memoizedCalculation'
,{ value : this.expensiveOperation()
,writable : false
});
return this.memoizedCalculation;
}
,configurable: true
}
});
}
TheConstructorJ.prototype.expensiveOperation = function() {
return this.side * this.side * this.side;
}
//Test code:
var instanceJ = new TheConstructorJ(2);
console.log("memoizedCalculation:"+instanceJ.memoizedCalculation);
instanceJ.memoizedCalculation = 42; // results in error
Run Code Online (Sandbox Code Playgroud)
生产:
memoizedCalculation:8
>Uncaught TypeError: Cannot assign to read only property 'memoizedCalculation' of object '#<TheConstructorJ>'
Run Code Online (Sandbox Code Playgroud)
OP的原始问题,从2011年3月7日开始,提出了基本的getter和setter语法,指出它在一个对象上工作但不在'this'上,并询问如何在构造函数中定义getter和setter.除了上面的所有示例之外,还有一种"廉价镜头"的方法:在构造函数中创建一个新对象,就像OP一样,但是然后将对象指定为'this'中的成员.所以,原始代码看起来像这样:
var MyClass = function(value) {
var test = !!value; // 'test' has to be a boolean
this.data = {
get test() { return test },
set test(value) { test = !!value }
};
};
var instance = new MyClass(true);
// But now 'data' is part of the access path
instance.data.test = 0;
console.log(instance.data.test);
Run Code Online (Sandbox Code Playgroud)
生产:
false
Run Code Online (Sandbox Code Playgroud)
信不信由你,我实际上遇到过这种"廉价拍摄"是最佳解决方案的情况.具体来说,当我将来自几个表中的记录封装在一个类中时,我使用了这种技术,并希望提供一个统一的视图,就像它们是一个名为"data"的记录一样.
玩得开心.
IAM_AL_X
更新ES6 - 看看Alex Rauschmayer的书探索ES6的第 19.3.1节http://exploringjs.com/es6/ch_maps-sets.html#sec_weakmaps-private-data,它演示了如何将WeakMaps与getter和setter一起使用保存私人数据.结合第16.2.2.3节http://exploringjs.com/es6/ch_classes.html#leanpub-auto-getters-and-setters会产生类似的结果
# module test_WeakMap_getter.js
var _MyClassProp = new WeakMap();
class MyClass {
get prop() {
return _MyClassProp.get( this );
}
set prop(value) {
_MyClassProp.set( this, value );
}
}
var mc = new MyClass();
mc.prop = 5 ;
console.log( 'My value is', mc.prop );
$ node --use_strict test_WeakMap_getter.js
My value is 5
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
22545 次 |
| 最近记录: |