在没有 defineProperty 的情况下覆盖对象 getter
Overriding object getter without defineProperty
我已经使用 Object.defineProperty
定义了 属性 和 getter,我希望能够覆盖它而无需使用 defineProperty
来防止对于将要使用它但可能不知道它不是 "normal" 属性 的同事来说,有任何困惑。我试过 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);
不过,我个人不会使用它,我想你可以解决这个问题,只在值特定于你的期望时才设置它,如果它不是正确的值,则抛出一些错误排序?
缺点当然是,一旦他们看到您像那样输入代码的位置,他们也可以这样做,但我想他们那时已经不那么困惑了;)我实际上更喜欢第二个我在底部显示的选项只是提供了一个额外的 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);
}
另一种方法可能只是将逻辑构建到 class 构造函数中,并在函数(或内部变量)上添加潜在 setter
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);
I've tried the writeable and configurable options to no avail.
writable
仅适用于数据属性,即具有 value
而不是 getter 和 setter.
的属性
configurable
只是允许删除和重定义,不让属性可设置。
如果您希望 fixture.email = 'bob';
不抛出错误,则必须在您的属性对象上提供一个 set
方法。此方法现在可能:
- 忽略新值
- 存储新值,例如在不同的 属性 或闭包变量中,以便 getter 可以在后续访问时产生它(@Icepickle 在他的回答中有一些这样的例子)
- 将访问器 属性 转换回 "normal" 一个
最后一个可能是最简单和最有价值的选择:
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
我已经使用 Object.defineProperty
定义了 属性 和 getter,我希望能够覆盖它而无需使用 defineProperty
来防止对于将要使用它但可能不知道它不是 "normal" 属性 的同事来说,有任何困惑。我试过 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);
不过,我个人不会使用它,我想你可以解决这个问题,只在值特定于你的期望时才设置它,如果它不是正确的值,则抛出一些错误排序?
缺点当然是,一旦他们看到您像那样输入代码的位置,他们也可以这样做,但我想他们那时已经不那么困惑了;)我实际上更喜欢第二个我在底部显示的选项只是提供了一个额外的 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);
}
另一种方法可能只是将逻辑构建到 class 构造函数中,并在函数(或内部变量)上添加潜在 setter
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);
I've tried the writeable and configurable options to no avail.
writable
仅适用于数据属性,即具有 value
而不是 getter 和 setter.
configurable
只是允许删除和重定义,不让属性可设置。
如果您希望 fixture.email = 'bob';
不抛出错误,则必须在您的属性对象上提供一个 set
方法。此方法现在可能:
- 忽略新值
- 存储新值,例如在不同的 属性 或闭包变量中,以便 getter 可以在后续访问时产生它(@Icepickle 在他的回答中有一些这样的例子)
- 将访问器 属性 转换回 "normal" 一个
最后一个可能是最简单和最有价值的选择:
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