不可设置和不可写属性仍然是可变的
Unsettable & Unwritable properties are still mutable
我正在尝试在构造函数中创建一个属性,该属性是不可变的,除非通过原型函数。我正在尝试关闭MDN文档:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties。但是似乎没有办法使属性完全不可变。考虑一个简单的例子:
function Test(){
Object.defineProperties(this,{
elems : { value : [] }
})
}
Test.prototype.addElem = function(newElem){
if (this.elems.indexOf(newElem) == -1){
this.elems.push(newElem);
}
};
在大多数情况下工作正常(不可分配(:
>a = new Test()
Object { , 1 more… }
>a.elems
Array [ ]
>a.elems = 10
10
>a.elems
Array [ ]
不幸的是,它仍然是可变的。考虑:
>a.elems.push(10)
1
>a.elems
Array [ 10 ]
我确信它们是其他函数(数组或对象方法?(,它们将更改不可写和不可设置属性的值。推只是我遇到的那个。有没有办法做到这一点?我知道一种可能的解决方案是:
function Test(){
var elems = [];
this.addElem = function(newElem){
if (elems.indexOf(newElem) == -1){
elems.push(newElem);
}
}
}
但是我已经读到这是内存效率低下的,特别是当"类"有很多实例时。另外,我正在研究的东西可能有很多这样的方法,所以我更担心内存方面的考虑。
有什么想法吗?我对JS原型的所有复杂性都不是很了解。
在 JavaScript 中,对象默认是可扩展的,但如果能够利用 ES5,您应该能够使用 Object.seal()
或 Object.freeze()
方法来获取不可变属性。
MDN 文档Object.freeze()
有一个示例,展示了如何递归冻结("deepFreeze"(对象的所有属性,有效地使其完全不可变。
下面是将问题中的代码与文档中的代码相结合的概念证明:
function Test() {
Object.defineProperties(this, {
elems : { value : [] }
})
}
Test.prototype.addElem = function(newElem) {
if (this.elems.indexOf(newElem) == -1) {
this.elems.push(newElem);
}
};
function deepFreeze(obj) {
// Retrieve the property names defined on obj
var propNames = Object.getOwnPropertyNames(obj);
// Freeze properties before freezing self
propNames.forEach(function(name) {
var prop = obj[name];
// Freeze prop if it is an object
if (typeof prop == 'object' && prop !== null)
deepFreeze(prop);
});
// Freeze self (no-op if already frozen)
return Object.freeze(obj);
}
a = new Test();
a.elems.push(1);
console.log(a.elems); // [1]
deepFreeze(a);
a.elems.push(2);
console.log(a.elems); // Error
在 FireBug 中,对象"深度冻结"后的a.elems.push()
返回TypeError
异常,指示该属性不可写;
类型错误:无法定义数组末尾以上的数组索引属性 具有不可写长度
Safari 检查器还会返回一个TypeError
异常:
类型错误: 试图分配给只读属性。
在闭包的帮助下,您在很大程度上可以完成此操作。 这就是你在 JavaScript 中实现隐私的方式。
简而言之,您在函数内部创建一个变量,并让该函数返回一个包含 setter/getter 的对象。
在我的示例中,foo 函数包含一个 _foo 变量,该变量只能由函数 foo 返回的对象中的方法设置。您正在有效地为函数 foo 范围内的 var 创建一个 API。
var foo = function(config){
if (!config) {
config = {};
}
//enclosed variable
var _foo = {
bar: []
};
if (config.bar) {//All item to be initialized with data
_foo.bar = config.bar;
}
var fooAPI = {
addBarItem: function(val){
_foo.bar.push(val);
return _foo.bar.length - 1;//return idenx of item added
},
removeBarItem: function(index) {
return _foo.bar.slice(index, 1);//return the removed item
},
getBarItem: function(index) {
return _foo.bar[index];//return the removed item
},
emptyBarItems: function() {
return _foo.bar.slice(0, _foo.bar.length);//return all removed
},
getBarItems: function(){
//clone bar do not return reference to it in order to keep private
var newBar = [];
_foo.bar.forEach(function(item){
newBar.push(item);
});
return newBar;
}
};
return fooAPI;
};
var myFoo = new foo({bar: ['alpha', 'beta', 'gamma']});
console.log(myFoo.getBarItems());
- 将脚本缓存到本地存储的basket.js概念仍然是一个好主意吗
- 浏览器仍然是单线程的吗
- 重新审视网站优化的经验法则:JavaScript在现代浏览器中仍然是必不可少的
- 调整图像大小以使其完美地适合幻灯片,问题仍然是用 for 循环将 CSS 代码替换为我的图像
- 为什么“使用严格”仍然是一个字符串字面
- jQuery .val('xxx') 不是设置值,而是 .attr('value', &
- 不可设置和不可写属性仍然是可变的
- 速度.js重置 {bottom, top} 为“auto” 不起作用,它仍然是“0px”
- 如何使用赋值而不是设置值
- 如何自动预选(而不仅仅是设置值)billing_state下拉列表与shipping_state下拉列表相同
- 持续时间为零的css转换是否仍然是硬件加速的
- getElementById仍然是“;“安全”;DOM操作方法
- 即使AngularJS和PHP的凭据不正确,登录仍然是直接的
- 如何设置IE浏览器模式而不是设置文档模式
- 函数是设置所有而不是每个
- 在Chrome中设置cookie,只是提供值和过期值,而不是设置
- 什么是“设置”HTML"相当于appendTo和prependTo
- 在Twitter Bootstrap 3按钮(复选框)仍然是灰色后,它是未检查的
- PHP飞到购物车效果jquery ajax /我想提交表单,但仍然是相同的页面
- Cordova/PhoneGap照片质量设置为1,仍然是高质量