重写不带defineProperty的对象getter
Overriding object getter without defineProperty
我已经使用Object.defineProperty
用getter定义了一个属性,我希望能够在不需要使用defineProperty
的情况下覆盖它,以防止那些将使用它但可能不知道它不是"正常"属性的同事感到困惑。我尝试过writeable
和configurable
选项,但都没有成功。
var fixture = {
name: 'foo',
color: 'green'
};
Object.defineProperty(fixture, 'email', {
get: function () {
return 'test+' + Date.now() + '@gmail.com';
},
configurable: true,
writeable: true
});
console.log(fixture.email); // test+<date>@gmail.com
fixture.email = 'bob'; // consumer attempts to overwrite
console.log(fixture.email); // test+<date>@gmail.com T_T
// this _will_ modify the property
Object.defineProperty(fixture, 'email', {
value: 'overwritten'
});
console.log(fixture.email);
我尝试过可写和可配置的选项,但都没有用。
writable
仅适用于数据属性,即具有value
而非getter和setter的属性。
configurable
只是允许删除和重新定义,而不是使属性可设置。
如果希望fixture.email = 'bob';
不抛出错误,则必须在attributes对象上提供set
方法。这种方法现在可以:
- 忽略新值
- 将新值存储在一个不同的属性或闭包变量中,这样getter就可以在随后的访问中生成它(@Icepicke在他的回答中有一些例子)
- 将访问者属性转换回"正常"属性
最后一种可能是最简单、最有回报的选择:
var fixture = {
name: 'foo',
color: 'green'
};
Object.defineProperty(fixture, 'email', {
get: function() {
return 'test+' + Date.now() + '@gmail.com';
},
set: function(val) {
Object.defineProperty(this, 'email', {
value: val,
writable: true
});
},
configurable: true,
enumerable: true
});
console.log(fixture.email); // test+<date>@gmail.com
fixture.email = 'bob'; // consumer attempts to overwrite
console.log(fixture.email); // bob
虽然我个人不会使用它,但我想你可以绕过这个问题,只在值特定于你的期望时设置它,如果它不是正确的值,就抛出某种错误?
当然,不利的一面是,一旦他们看到你把代码放在代码中的地方,他们也可以这样做,但我想他们那时已经不那么困惑了;)实际上,我更喜欢我在底部提供的第二个选项,它只是提供了一个额外的setEmail方法来自行设置,或者通过内部更新"DataContainer"中的props.email属性
var data = {
foo: 'foo',
bar: 'bar'
};
Object.defineProperty(data, 'email', {
get: function() {
if (typeof this._props === 'undefined') {
this._props = {};
}
return this._props.email;
},
set: function(val) {
if (!val || !val.private) {
throw 'no access exception';
}
if (this.email === val) {
return;
}
this._props.email = val.email;
},
configurable: false
});
console.log(data.email);
data.email = {
private: 1,
email: 'hey.you@somewhere.hi'
};
console.log(data.email);
try {
data.email = 'not allowed to set';
} finally {
console.log(data.email);
}
另一种方法可能只是将逻辑构建到类构造函数中,并在函数(或变量内部)上添加一个潜在值设置器
function DataContainer(options) {
var createProp = function(obj, propertyName, propertyHolder, isReadOnly) {
Object.defineProperty(obj, propertyName, {
get: function() {
return propertyHolder[propertyName];
},
set: function(val) {
if (isReadOnly) {
return;
}
propertyHolder[propertyName] = val;
},
configurable: false
});
if (isReadOnly) {
obj['set' + propertyName[0].toUpperCase() + propertyName.substr(1)] = function(val) {
//internal setter
propertyHolder[propertyName] = val;
};
}
},
prop = {},
fieldProp, fieldVal, ro;
if (options && options.fields) {
for (fieldProp in options.fields) {
if (options.fields.hasOwnProperty(fieldProp)) {
fieldVal = options.fields[fieldProp];
ro = false;
if (typeof fieldVal === 'object' && fieldVal.value) {
ro = fieldVal.readOnly || false;
prop[fieldProp] = fieldVal.value;
} else {
prop[fieldProp] = fieldVal;
}
createProp(this, fieldProp, prop, ro);
}
}
}
}
var data = new DataContainer({
fields: {
foo: 'foo',
bar: 'bar',
email: {
value: 'test@something.com',
readOnly: true
}
}
});
console.log(data);
data.email = 'test@test.com';
console.log(data.email);
data.setEmail('test@test.com');
console.log(data.email);
相关文章:
- 查看JS对象的所有键,甚至是getter定义的键
- 重写不带defineProperty的对象getter
- JavaScript 对象中的私有成员,带有 getter 和 setter
- localStorage-对象的getter-, setter-方法的目的是什么?
- 什么类型的对象/属性是原型getter和setter
- CoffeeScript:对象初始化程序中的Getter/Setter
- 对象描述符getter/setter在最近的Chrome/V8版本中的性能
- 这个 getter-setter 闭包是否有充分的理由以这种方式在其内部对象中声明它是私有的
- JavaScript 对象和 getter 属性
- 在对象上定义 getter,以便所有未定义的属性查找都返回 “”
- 如何定义一个构造函数,该函数使用 getter 和 setter 创建对象
- 将 JavaScript 对象转换为 ClojureScript:getter 和 setter properites
- 访问 JavaScript 对象的默认 getter/setter
- 带有对象键的Javascript setter和getter
- 使用object.assign()添加到对象中的getter发现闭包变量的值错误
- 具有自身内在价值的对象.另一种做getter的方法
- 如何克隆包含getter和setter的JavaScript对象
- 对象getter/setter与新构造函数的比较-测试结果
- 对象getter别名
- 如何修改由对象getter返回的私有变量?