【问题标题】:Can Read-Only Properties be Implemented in Pure JavaScript?可以在纯 JavaScript 中实现只读属性吗?
【发布时间】:2010-09-26 20:00:48
【问题描述】:

查看mozilla documentation,查看正则表达式示例(标题为“使用匹配结果创建数组”),我们有如下语句:

input:一个只读属性,反映与正则表达式匹配的原始字符串。

index:只读属性,是字符串中匹配项的从零开始的索引。

等等... 是否可以在 JavaScript 中创建您自己的具有只读属性的对象,或者这是为特定浏览器实现的内置类型保留的特权?

【问题讨论】:

标签: javascript browser


【解决方案1】:

编辑: 自从编写了这个答案后,在 EcmaScript 5 中使用 Object.defineProperty 的一种新的、更好的方法已经标准化,并支持更新的浏览器。见Aidamina's answer。如果您需要支持“旧”浏览器,您可以使用此答案中的一种方法作为后备。


在 Firefox、Opera 9.5+ 和 Safari 3+、Chrome 和 IE(使用 v11 测试)中,您可以定义 getter 和 setter 属性。如果您只定义一个 getter,它会有效地创建一个只读属性。您可以在对象字面量中或通过调用对象上的方法来定义它们。

var myObject = {
    get readOnlyProperty() { return 42; }
};

alert(myObject.readOnlyProperty); // 42
myObject.readOnlyProperty = 5;    // Assignment is allowed, but doesn't do anything
alert(myObject.readOnlyProperty); // 42

如果你已经有对象,可以调用__defineGetter____defineSetter__

var myObject = {};
myObject.__defineGetter__("readOnlyProperty", function() { return 42; });

当然,这在网络上并不是很有用,因为它在 Internet Explorer 中不起作用。

您可以从John Resig's blogMozilla Developer Center 了解更多信息。

【讨论】:

  • 好一个!我测试过,它适用于 Firefox、Opera 和 Chrome,但不适用于 IE。
  • 附加说明 - 这是任何 javascript 规范的一部分吗?
  • 它不是当前规范的一部分。我相信它计划用于下一版本的 ECMAScript,但现在,它只是一个 Mozilla 扩展,在其他一些浏览器中得到支持。
  • 仍然不受 IE 支持 ;)
  • 对于您的实用程序,IE 从第 9 版开始支持此技术。这是一个很好的兼容性表:kangax.github.io/es5-compat-table
【解决方案2】:

使用any javascript interpreter that implements ECMAScript 5,您可以使用 Object.defineProperty 来定义只读属性。在松散模式下,解释器将忽略对属性的写入,在严格模式下,它会抛出异常。

来自ejohn.org的示例:

var obj = {};
Object.defineProperty( obj, "<yourPropertyNameHere>", {
  value: "<yourPropertyValueHere>",
  writable: false,
  enumerable: true,
  configurable: true
});

【讨论】:

  • 注意:这个是兼容IE9+的,所以今天还是well supported
【解决方案3】:

在 JavaScript 中可以有通过 getter 方法可用的只读属性。这通常称为“模块”模式。

YUI 博客有一篇很好的文章:http://yuiblog.com/blog/2007/06/12/module-pattern/

来自帖子的片段:

YAHOO.myProject.myModule = function () {

//"private" variables:
var myPrivateVar = "I can be accessed only from within YAHOO.myProject.myModule.";

//"private" method:
var myPrivateMethod = function () {
    YAHOO.log("I can be accessed only from within YAHOO.myProject.myModule");
}

return  {
    myPublicProperty: "I'm accessible as YAHOO.myProject.myModule.myPublicProperty."
    myPublicMethod: function () {
        YAHOO.log("I'm accessible as YAHOO.myProject.myModule.myPublicMethod.");

        //Within myProject, I can access "private" vars and methods:
        YAHOO.log(myPrivateVar);
        YAHOO.log(myPrivateMethod());

        //The native scope of myPublicMethod is myProject; we can
        //access public members using "this":
        YAHOO.log(this.myPublicProperty);
    }
};

}(); // the parens here cause the anonymous function to execute and return

【讨论】:

    【解决方案4】:

    这里是只读属性或变量。

    作为aidamina said,顺便说一下,这是一个用于测试的简短代码,现在非常有用,因为 JQuery 假装弃用了选择器属性。

    <script>
    Object.defineProperties(window, {
      "selector": { value: 'window', writable: false }
    });
    
    alert (window.selector);  // outputs window
    
    selector ='ddd';          // testing because it belong to the global object
    alert (window.selector);  // outputs window
    alert (selector);         // outputs window
    
    window.selector='abc';
    alert (window.selector);   // outputs window
    alert (selector);          // outputs window
    </script>
    

    所以你已经测试了一个只读属性或变量。

    【讨论】:

    • 我不敢相信这没有更多的赞成票。你知道它是如何工作的吗?
    【解决方案5】:

    是的,我们可以在 JavaScript 中为对象设置只读属性。可以通过私有变量和object.defineProperty()方法实现,

    请参阅以下示例,该示例说明了具有只读属性的对象,

    function Employee(name,age){
        var _name = name;
        var _age = age;
    
        Object.defineProperty(this,'name',{
            get:function(){
                return _name;
            }
        })
    }
    
    var emp = new Employee('safeer',25);
    console.log(emp.name); //return 'safeer'
    emp.name='abc';
    console.log(emp.name); //again return 'safeer', since name is read-only property
    

    【讨论】:

      【解决方案6】:

      这是 Douglas Crockford 的“Javascript 中的私人成员”页面的链接......在我看来,只有在提供 getter 方法而不提供 setter 时,这些页面才会被读取:

      http://javascript.crockford.com/private.html

      【讨论】:

      • privatereadonly 是有区别的。私有变量(以及 Crockford 在 JavaScript 中实现它的方式)只是 private,这意味着可以在类(构造函数)内部访问,但不能暴露在外部,因此显然您无法更改无法访问的内容。只读属性可以对外公开但不能更改。
      • 真的有必要对 5 年半前 前的仅链接答案投反对票吗?当时的限制还没有到位
      【解决方案7】:

      您会看到我已经为颜色定义了一个 setter 和 getter,因此可以对其进行修改。另一方面,一旦定义了对象,品牌就会变成只读的。我相信这是您正在寻找的功能。

              function Car(brand, color) {
                  brand = brand || 'Porche'; // Private variable - Not accessible directly and cannot be frozen
                  color = color || 'Red'; // Private variable - Not accessible directly and cannot be frozen
                  this.color = function() { return color; }; // Getter for color
                  this.setColor = function(x) { color = x; }; // Setter for color
                  this.brand = function() { return brand; }; // Getter for brand
                  Object.freeze(this); // Makes your object's public methods and properties read-only
              }
      
              function w(str) {
                  /*************************/
                  /*choose a logging method*/
                  /*************************/
                  console.log(str);
                  // document.write(str + "<br>");
              }
      
              var myCar = new Car;
              var myCar2 = new Car('BMW','White');
              var myCar3 = new Car('Mercedes', 'Black');
      
              w(myCar.brand()); // returns Porche
              w(myCar.color()); // returns Red
      
              w(myCar2.brand()); // returns BMW
              w(myCar2.color()); // returns White
      
              w(myCar3.brand()); // returns Mercedes
              w(myCar3.color()); // returns Black
      
              // This works even when the Object is frozen
              myCar.setColor('Green');
              w(myCar.color()); // returns Green
      
              // This will have no effect
              myCar.color = 'Purple';
              w(myCar.color()); // returns Green
              w(myCar.color); // returns the method
      
              // This following will not work as the object is frozen
              myCar.color = function (x) {
                  alert(x);
              };
      
              myCar.setColor('Black');
              w(
                  myCar.color(
                      'This will not work. Object is frozen! The method has not been updated'
                  )
              ); // returns Black since the method is unchanged
      

      以上内容已在 Chromium 版本 41.0.2272.76 Ubuntu 14.04 上进行了测试,并产生了以下输出:

                Porche
                Red
                BMW
                White
                Mercedes
                Black
                Green
                Green
                function () { return color; }
                Black
      

      【讨论】:

      • +1。这个答案提示使用Object.freeze()。 ECMAScript 5 添加了Object.sealObject.freeze 方法。 seal 方法将阻止属性添加,但允许写入/编辑属性。 Object.freeze 方法将完全锁定一个对象,它们将保持原样
      【解决方案8】:

      bob.js framework 提供了一种声明只读属性的方法。在底层,它声明了一个私有字段并为其公开了 getter/setter 函数。 bob.js 提供了多种方式来做同样的事情,具体取决于便利性和特定目标。这是使用Property 的面向对象实例的一种方法(其他方法允许在对象本身上定义setter/getter):

      var Person = function(name, age) {  
          this.name = new bob.prop.Property(name, true); 
          var setName = this.name.get_setter(); 
          this.age = new bob.prop.Property(age, true); 
          var setAge = this.age.get_setter();  
          this.parent = new bob.prop.Property(null, false, true);  
      };  
      var p = new Person('Bob', 20);  
      p.parent.set_value(new Person('Martin', 50));  
      console.log('name: ' + p.name.get_value());  
      console.log('age: ' + p.age.get_value());  
      console.log('parent: ' + (p.parent.get_value ? p.parent.get_value().name.get_value() : 'N/A')); 
      // Output: 
      // name: Bob 
      // age: 20 
      // parent: N/A 
      

      最后,p.name.set_value 没有定义,因为这是一个只读属性。

      【讨论】:

        【解决方案9】:

        因此,它仅在尚未定义的情况下才有效,但是您可以使用 const 将变量设为只读。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-01-01
          • 2011-04-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-07
          相关资源
          最近更新 更多