在 JavaScript 中定义只读属性
Posted
技术标签:
【中文标题】在 JavaScript 中定义只读属性【英文标题】:Defining read-only properties in JavaScript 【发布时间】:2011-12-07 03:00:27 【问题描述】:给定一个对象obj
,我想定义一个只读属性'prop'
,并将其值设置为val
。这是正确的做法吗?
Object.defineProperty( obj, 'prop',
get: function ()
return val;
);
结果应该是(对于val = 'test'
):
obj.prop; // 'test'
obj.prop = 'changed';
obj.prop; // still 'test' since it's read-only
此方法有效:http://jsfiddle.net/GHMjN/ 我只是不确定这是否是最简单/最顺畅/最合适的方法......
【问题讨论】:
可能重复:***.com/questions/366047/…(如果你不想支持旧版浏览器,你的方法是最好的) 【参考方案1】:您可以改用属性描述符的writable
属性,这样就不需要get
访问器:
var obj = ;
Object.defineProperty(obj, "prop",
value: "test",
writable: false
);
如 cmets 中所述,writable
选项默认为 false
,因此在这种情况下您可以省略它:
Object.defineProperty(obj, "prop",
value: "test"
);
这是 ECMAScript 5,因此无法在旧版浏览器中运行。
【讨论】:
我不确定我的代码和您的代码是否“在外部”产生完全相同的结果,但您的方法无疑是更合适的方法。 根据 MDN 文档,Object.defineProperty(obj, "prop", value:"test");
等价于上面的代码,因为 writable 默认设置为 false。
请注意,最终对象/数组的 subProperties仍然可以修改。在这种情况下,只有“prop”键不能重新分配。【参考方案2】:
在新浏览器或 node.js 中,可以使用 Proxy 创建只读对象。
var obj =
prop: 'test'
obj = new Proxy(obj ,
setProperty: function(target, key, value)
if(target.hasOwnProperty(key))
return target[key];
return target[key] = value;
,
get: function(target, key)
return target[key];
,
set: function(target, key, value)
return this.setProperty(target, key, value);
,
defineProperty: function (target, key, desc)
return this.setProperty(target, key, desc.value);
,
deleteProperty: function(target, key)
return false;
);
您仍然可以为该对象分配新属性,它们也是只读的。
示例
obj.prop
// > 'test'
obj.prop = 'changed';
obj.prop
// > 'test'
// New value
obj.myValue = 'foo';
obj.myValue = 'bar';
obj.myValue
// > 'foo'
【讨论】:
【参考方案3】:由于旧浏览器(向后兼容),我不得不想出属性的访问器函数。我使它成为bob.js 的一部分:
var obj = ;
//declare read-only property.
bob.prop.namedProp(obj, 'name', 'Bob', true);
//declare read-write property.
bob.prop.namedProp(obj, 'age', 1);
//get values of properties.
console.log(bob.string.formatString('0 is 1 years old.', obj.get_name(), obj.get_age()));
//set value of read-write property.
obj.set_age(2);
console.log(bob.string.formatString('Now 0 is 1 years old.', obj.get_name(), obj.get_age()));
//cannot set read-only property of obj. Next line would throw an error.
// obj.set_name('Rob');
//Output:
//========
// Bob is 1 years old.
// Now Bob is 2 years old.
希望对你有帮助。
【讨论】:
等等,.namedProp(obj, 'foo')
,在对象本身上创建.get_foo()
,/.set_foo()
?这不是很有效。我想我会带一个包装器,例如X(obj).set('foo')
/X(obj).get('foo')
.
澄清:我认为我们在谈论两个不同的事情。您可能希望保持真实对象不变,同时对其进行包装;但我建议更改真实对象并具有表示属性的函数。因为为了向后兼容,旧式 javascript 属性可能被视为字段。因此,您需要为其提供访问器(函数)(另外我建议从真实对象中删除传统的 JS 属性,从而完全控制这些属性)。至于包装器,这也不错,但与我的方法不同。【参考方案4】:
我试过了,效果很好……
element.readOnly = "readOnly" (then .readonly-> true)
element.readOnly = "" (then .readonly-> false)
【讨论】:
在代码 sn-p 中提供您的答案。现在还不够清楚【参考方案5】:在我的例子中,我需要一个对象,我们只能设置它的属性一次。 所以当有人试图改变已经设置的值时,我让它抛出一个错误。
class SetOnlyOnce
#innerObj = ; // private field, not accessible from outside
getCurrentPropertyName()
const stack = new Error().stack; // probably not really performant method
const name = stack.match(/\[as (\w+)\]/)[1];
return name;
getValue()
const key = this.getCurrentPropertyName();
if(this.#innerObj[key] === undefined)
throw new Error('No global param value set for property: ' + key);
return this.#innerObj[key];
setValue(value)
const key = this.getCurrentPropertyName();
if(this.#innerObj[key] !== undefined)
throw new Error('Changing global parameters is prohibited, as it easily leads to errors: ' + key)
this.#innerObj[key] = value;
class GlobalParams extends SetOnlyOnce
get couchbaseBucket() return this.getValue()
set couchbaseBucket(value) this.setValue(value)
get elasticIndex() return this.getValue()
set elasticIndex(value) this.setValue(value)
const _globalParams = new GlobalParams();
_globalParams.couchbaseBucket = 'some-bucket';
_globalParams.elasticIndex = 'some-index';
console.log(_globalParams.couchbaseBucket)
console.log(_globalParams.elasticIndex)
_globalParams.elasticIndex = 'another-index'; // ERROR is thrown here
console.log(_globalParams.elasticIndex)
【讨论】:
以上是关于在 JavaScript 中定义只读属性的主要内容,如果未能解决你的问题,请参考以下文章
get定义方法——Javascript设置对象属性为"只读"