【问题标题】:What is the preferred way to define properties for Google Closure classes?为 Google Closure 类定义属性的首选方法是什么?
【发布时间】:2012-08-31 07:58:06
【问题描述】:

下面的示例显示了一个扩展 goog.ui.Component 的类。

类的属性应该如下所示在构造函数之外定义,还是应该只在构造函数中内联定义?

可以将属性初始化为null吗?

goog.provide("org.something.SomeClass");

/**
 * @type {Object}
 * @private
 **/
org.something.SomeClass.prototype.anObject_ = null;

/**
 * @type {Element}
 * @private
 **/
org.something.SomeClass.prototype.anElement_ = null;

/**
 * @param {goog.dom.DomHelper=} opt_domHelper
 * @constructor
 * @extends {goog.ui.Component}
*/
org.something.SomeClass = function () {
    goog.ui.Component.call(this, opt_domHelper);

    this.anObject_ = {};
    this.anElement_ = new Element();
};
goog.inherits(org.something.SomeClass, goog.ui.Component);

【问题讨论】:

    标签: javascript google-closure google-closure-library


    【解决方案1】:

    Closure Library 实现了具有在原型上以及在构造函数中定义的属性的类。除了研究闭包库源代码之外,还有一些问题需要在决定是在原型上还是在构造函数中定义属性时考虑。

    类的每个实例的属性是否唯一?

    每个实例唯一的属性(例如汽车的 VIN 号)不应在实例之间共享,因此在构造函数中而不是原型中定义。

    /**
     * A car.
     * @param {string} vin The Vehicle Identification Number.
     * @constructor
     */
    Car = function(vin) {
    
      /**
       * The Vehicle Identification Number.
       * @type {string}
       * @private
       */
      this.vin_ = vin;
    }; 
    

    属性类型是不可变的(例如字符串、布尔值、数字)还是可变的(例如对象、数组)?

    由于不可变的属性类型可以在实例之间安全地共享,它们应该在原型上定义。如果一个实例需要覆盖共享的默认值,可以添加一个实例属性来隐藏同名的原型属性。

    /**
     * The number of cylinders in the engine.
     * @type {number}
     * @private
     */
    Car.prototype.cylinders_ = 4;
    
    /**
     * Sets the number of cylinders in the engine.
     * @param {number} cylinders The number of cylinders.
     */
    Car.prototype.setCylinders = function(cylinders) {
      if (this.cylinders_ == cylinders) {
        // Since the number of cylinders has not changed, do not add a new
        // instance property to shadow the prototype property. Instead, continue
        // to use the prototype property.
        return;
      }
    
      // Defines cylinders_ property on the instance object that shadows
      // Car.prototype.cylinders_
      this.cylinders_ = cylinders;
    };
    
    /**
     * Gets the number of cylinders in the engine.
     * @return {number} The number of cylinders.
     */
    Car.prototype.getCylinders = function() {
      return this.cylinders_;
    };
    

    以下示例说明设置实例属性如何影响原型属性。

    var myCar = new Car("1HGCM82633A004352");
    alert(myCar.getCylinders()); // Alerts 4.
    
    myCar.setCylinders(6);
    alert(myCar.getCylinders()); // Alerts 6;
    
    // Delete the instance property and let the prototype property
    // "shine through".
    delete myCar.cylinders_;
    alert(myCar.getCylinders()); // Alerts 4;
    


    如果属性类型是可变的,例如 Array 或 Object,那么在大多数情况下,您不希望在类的实例之间共享相同的可变属性实例。因此,可变属性通常在构造函数中定义,而不是在原型中。

    可以将属性初始化为null吗?

    在闭包库中有很多例子,其中属性被初始化为null. 但是,如果可能的话,最好将变量初始化为有用的默认值,例如将默认柱面数设置为 4,如上例所示。

    【讨论】:

      【解决方案2】:

      我还怀疑它是为了优化 V8 引擎以及闭包编译器。如果所有对象都具有相同的属性,V8 引擎会缓存类实例(IO2012 talk)。通过在原型中声明所有内容,所有对象实例都具有有序相同的属性。或者他们可能只是想拥有清晰的风格。 :-)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-14
        • 1970-01-01
        • 2023-03-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多