可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
How come constants cannot be set as properties of objects which are variables themselves?
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
And how come constants passed by reference suddenly become variable? EDIT: I know App won't (or rather... SHOULDN'T) be mutable; this is just an observation...
(function() { const App; // bunch of code window.com_namespace = App; }()); window.com_namespace; // App window.com_namespace = 'something else'; window.com_namespace; // 'something else'
How can a nicely organized, extensible, object-oriented, singly namespaced library containing constants be made with these limitations?
EDIT: I believe zi42, but I just have to ask why
回答1:
You cannot do it with constants. The only possible way to do something that behaves like you want, but is not using constants, is to define a non-writable property:
var obj = {}; Object.defineProperty( obj, "MY_FAKE_CONSTANT", { value: "MY_FAKE_CONSTANT_VALUE", writable: false, enumerable: true, configurable: true });
Regarding your question as to why a const
passed to a function becomes variable, the answer is because it's passed by value and not by reference. The function is getting a new variable that has the same value as your constant.
edit: thanks to @pst for noting that objects literals in javascript are not actually "passed by reference", but using call-by-sharing:
Although this term has widespread usage in the Python community, identical semantics in other languages such as Java and Visual Basic are often described as call-by-value, where the value is implied to be a reference to the object.
回答2:
const person = { name: "Nicholas" }; // works person.name = "Greg"; console.log(person) //Greg
That's why use Object.defineProperty
回答3:
There is a far simpler way to do this. I like this pattern. Simple Objects.
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 is doing the work here
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
if you want you can leave the static property off the instance by leaving it off the object literal return on the constructor function.
const will only make it a read-only reference. As soon as you assign it, like here in a object literal it becomes a property of the constructed object.
回答4:
You should not forgot than the const declaration "creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned"
The const keyword work in a similar way than 'let', so you can redeclare it in an other block
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
Just like @ziad-saab mantioned if you want an object property than act like a constant, you have to define it as a non-writable property.
if your constant is an object and is property should not change, use Object.freeze() to make the object immutable.
(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