【问题标题】:How to create Javascript constants as properties of objects using const keyword?如何使用 const 关键字创建 Javascript 常量作为对象的属性?
【发布时间】:2012-06-06 07:10:25
【问题描述】:

为什么不能将常量设置为本身就是变量的对象的属性?

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

为什么通过引用传递的常量突然变成了变量? 编辑:我知道 App 不会(或者更确切地说......不应该)是可变的;这只是一个观察...

(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

【问题讨论】:

    标签: javascript object properties constants


    【解决方案1】:

    你不能用常量来做到这一点。唯一可能的方法是定义一个不可写的属性:

    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)中,相同的语义通常被描述为按值调用,其中的值被暗示为对对象的引用。

    【讨论】:

    • 对象不是通过引用传递的吗?
    • 是的,但是const obj = {} 有点没用,因为引用是不变的,但你仍然可以修改对象。
    • 没有。对象不是“通过引用传递”(这充其量是一个模棱两可的短语)。实现通常会“通过引用的”,但重要的是JavaScript 有Call By Object Sharing semantics。有趣的事实:ECMAScript 规范不使用术语“参考”
    • @pst——“引用”这个词最肯定使用了:reference type 是一个规范工件,用于解释(除其他外)值的分配是如何工作的。甚至还有语句“允许函数调用返回引用”。
    • 如果你试图改变它的值,它不会改变,但你也不会得到错误! obj.MY_FAKE_CONSTANT = "别的东西"; // 没有错误。
    【解决方案2】:
    const person = {
        name: "Nicholas"
    };
    
    // works
    person.name = "Greg";
    
    
    
    console.log(person) //Greg 
    

    这就是为什么使用 Object.defineProperty

    【讨论】:

      【解决方案3】:

      有一种更简单的方法可以做到这一点。我喜欢这种模式。简单对象。

      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 只会使其成为只读引用。一旦你分配它,就像这里的对象字面量一样,它就成为构造对象的属性。

      【讨论】:

        【解决方案4】:
        var obj = {};
        Object.defineProperty( obj, "MY_FAKE_CONSTANT", {
          value: "MY_FAKE_CONSTANT_VALUE",
          writable: false,
          enumerable: true,
          configurable: false // instead of true
        });
        

        我们还应该将 configurable 设置为 false 以防止属性从 obj 中删除

        delete obj.MY_FAKE_CONSTANT;
        

        如果 configurabletrue,则在该行之后,我们不再有 MY_FAKE_CONSTANT

        Reference

        【讨论】:

          【解决方案5】:

          你不应该忘记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
          

          【讨论】:

            【解决方案6】:

            我认为您应该在 Object.defineProperty 中定义可配置的属性中的常量:false 和可写:false,如果您保留可配置:true 那么您仍然可以更改该属性

            例如:当你在 Object.defineProperty 中设置 configure: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 只会遍历可枚举的属性

            【讨论】:

              猜你喜欢
              • 2012-06-06
              • 2014-09-15
              • 2016-05-14
              • 1970-01-01
              • 1970-01-01
              • 2016-12-03
              • 2016-02-25
              • 1970-01-01
              • 2022-12-04
              相关资源
              最近更新 更多