为什么不能将常量设置为变量本身的对象的属性?
const a = 'constant' // all is well
// set constant property of variable object
const window.b = 'constant' // throws Exception
// OR
var App = {}; // want to be able to extend
const App.goldenRatio= 1.6180339887 // throws Exception
为什么通过引用传递的常量突然变得可变? 编辑:我知道应用程序不会(或者更确切地说......)不可变;这只是一个观察......
(function() {
const App;
// bunch of code
window.com_namespace = App;
}());
window.com_namespace; // App
window.com_namespace = 'something else';
window.com_namespace; // 'something else'
如何使用这些限制来构建一个包含常量的组织良好,可扩展,面向对象的单一命名空间的库?
编辑:我相信zi42,但我只需要问why
答案 0 :(得分:46)
你不能用常数来做。执行行为类似但不使用常量的唯一可行方法是定义不可写属性:
var obj = {};
Object.defineProperty( obj, "MY_FAKE_CONSTANT", {
value: "MY_FAKE_CONSTANT_VALUE",
writable: false,
enumerable: true,
configurable: true
});
关于为什么传递给函数的const
变为变量的问题,答案是因为它是通过值而不是通过引用传递的。该函数获取一个与常量具有相同值的新变量。
编辑:感谢@pst注意到javascript中的对象文字实际上并未“通过引用传递”,而是使用call-by-sharing:
虽然这个术语在Python社区中有广泛的用法,但其他语言(如Java和Visual Basic)中的相同语义通常被描述为call-by-value,其中值隐含为对象的引用。
答案 1 :(得分:6)
const person = {
name: "Nicholas"
};
// works
person.name = "Greg";
console.log(person) //Greg
这就是使用Object.defineProperty
的原因答案 2 :(得分:5)
有一种更简单的方法可以做到这一点。我喜欢这种模式。简单的对象。
window.Thingy = (function() {
const staticthing = "immutable";
function Thingy() {
let privateStuff = "something";
function get() {
return privateStuff;
}
function set(_) {
privateStuff = _;
}
return Object.freeze({
get,
set,
staticthing
});
}
Thingy.staticthing = staticthing;
return Object.freeze(Thingy);
})();
let myThingy = new Thingy();
Thingy.staticthing = "fluid";
myThingy.staticthing = "fluid";
console.log(Thingy.staticthing); // "immutable"
console.log(myThingy.staticthing); // "immutable"
Object.freeze正在做这里的工作
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
如果你想要,你可以将静态属性从实例中移开,方法是将它从构造函数的对象文字返回处移开。
const只会使它成为只读参考。一旦你分配它,就像在对象文字中一样,它就成了构造对象的属性。
答案 3 :(得分:5)
var obj = {};
Object.defineProperty( obj, "MY_FAKE_CONSTANT", {
value: "MY_FAKE_CONSTANT_VALUE",
writable: false,
enumerable: true,
configurable: false // instead of true
});
我们还应将可配置设置为 false ,以防止该属性从obj中删除
delete obj.MY_FAKE_CONSTANT;
可配置为 true ,在该行之后,我们不再拥有 MY_FAKE_CONSTANT 。
答案 4 :(得分:3)
您不应忘记const declaration"创建对值的只读引用。它并不意味着它拥有的值是不可变的,只是变量标识符不能被重新分配"
const关键字以类似于' let'的方式工作,因此您可以在其他块中重新声明它
const MyConst = 5;
console.log('global MyConst =', MyConst); //global MyConst = 5
if(true){
const MyConst = 99
console.log('in if block, MyConst =', MyConst); //in if block, MyConst = 99
}
console.log('global MyConst still 5 ?', MyConst===5); //global MyConst still 5 ? true
就像@ ziad-saab提到的那样,如果你想要一个对象属性而不是一个常量,你必须将它定义为一个不可写的属性。
如果你的常量是一个对象而且属性不应该改变,那么使用Object.freeze()使对象不可变。
(function(){
var App = { };
// create a "constant" object property for App
Object.defineProperty(App , "fixedStuff", {
value: Object.freeze({ prop:6 }),
writable: false,
enumerable: true,
configurable: true
});
Object.defineProperty(window, "com_namespace", {
value: App,
writable: false,
enumerable: true,
configurable: true
});
})()
com_namespace.newStuff = 'An extension';
com_namespace.fixedStuff.prop = 'new value'; // do nothing!
console.log(com_namespace.fixedStuff.prop); //6
答案 5 :(得分:1)
我认为您应该在Object.defineProperty中的属性中定义一个常量,使其可配置:false和writable:false,如果您将configurable:true保留,则仍可以对该属性进行更改
例如:当您在Object.defineProperty中设置configurable:true时
cosnt obj = {name: 'some name'};
Object.defineProperty(obj, 'name', {
enumerable: true,
configurable: true,
writable: false
});
使用此方法,您将obj.name设置为“ constant”(常量),但是您可以这样做
Object.defineProperty(obj, 'name', {
enumerable: true,
configurable: true,
writable: true // <-- you can set to true because configurable is true
})
但是,如果将configurable设置为false,则永远无法编辑可写属性。
Object.defineProperty(obj, 'name', {
enumerable: true,
configurable: false, // <-- with this you never could edit writable property
writable: false
})
对于所有属性,您都可以使用Object.freeze
Object.freeze(obj);
Object.freeze将仅迭代可枚举的属性