【问题标题】:JavaScript accessor properties in constructors构造函数中的 JavaScript 访问器属性
【发布时间】:2016-08-06 23:07:18
【问题描述】:

我已经看到通过对象字面量和属性描述符中的 getset 关键字定义的访问器属性。

(来自Speaking JavaScript):

// Object literal
var obj = {
    get foo() {
        return 'getter';
    },
    set foo(value) {
        console.log('setter: '+value);
    }
};

// Property descriptor
var obj = Object.create(
    Object.prototype, {  // object with property descriptors
        foo: {  // property descriptor
            get: function () {
                return 'getter';
            },
            set: function (value) {
                console.log('setter: '+value);
            }
        }
    }
);

(来自Eloquent JavaScript):

// Adding to an object's prototype
Object.defineProperty(TextCell.prototype, "heightProp", {
  get: function() { return this.text.length; }
});

但是假设您正在使用 构造函数 来创建对象。我还没有看到在构造函数本身中定义访问器的示例(即,访问器是对象自己的属性。)

在构造函数中使用Object.defineProperty 似乎有效:

function V(x, y) {
    this.x = x;
    this.y = y;
    // accessor (getter) `length`
    Object.defineProperty(this, 'length', {
      get: function () { return Math.sqrt(this.x*this.x + this.y*this.y); } // (1)
    });
}

上面构造函数中(1)中定义的访问器属性和早期模式中定义的访问器属性(对象字面量,直接在对象上的属性描述符)有什么区别吗?

(除了编​​码风格偏好之外,是否有客观的理由不在构造函数中定义 getter 和 setter?)

【问题讨论】:

    标签: javascript oop design-patterns constructor


    【解决方案1】:

    当您使用函数构造函数模式创建一个新实例对象时,在您创建的每个实例的代码中,您将拥有一个作为函数(即另一个对象)的 getter,因此您为每个实例创建两个对象。相反,在将 getter 方法附加到原型的其他解决方案中,您将只有一个用于创建的所有对象的 getter。此外,在对象字面量表示法中,configurableenumerable 属性默认为 true,而函数 defineProperty 默认为 false,但您可以在 @ 中显式设置这些属性来解决此差异987654326@函数或者你可以这样做:

    function V(x, y) {
        return { x,
                 y,
                 get length(){
                    return Math.sqrt(this.x*this.x + this.y*this.y);
                 }
               };
        }
    

    您可以在构造函数中使用对象文字表示法返回对象。注意 ES6 属性值 shortand。这样,可配置和可枚举的将是true 用于length property

    【讨论】:

      【解决方案2】:

      上面构造函数中(1)中定义的访问器属性和早期模式中定义的访问器属性(对象字面量,直接在对象上的属性描述符)有什么区别吗?

      Object.definePropertyObject.defineProperties 允许对 getter/setter 的定义方式进行更细粒度的控制。

      (除了编​​码风格偏好之外,是否有客观原因不在构造函数中定义 getter 和 setter?)

      是的,取决于你的目的。

      prototype的优势:

      1. 添加到原型的方法由每个实例共享。尽管新实例可能很便宜,但将其添加到原型中的内存和操作码总是更少。
      2. 许多代码提示将包含原型属性和方法,但不包括仅在构造函数中设置的那些。
      3. 在原型中包含该属性可能表明它尚未被实例覆盖。
      4. 这是现代的 ECMAScript 方式。
      ([]).hasOwnProperty('length') // true, old pre-getter array.
      (new Uint8Array(1)).hasOwnProperty('length') // false, new typed array.
      

      每个实例的优点:

      您可以访问构造函数闭包的私有属性,这对于某些事情可能是可取的(WeakMap 可能使这完全没有必要)。

      【讨论】:

        【解决方案3】:

        上面构造函数中(1)中定义的访问器属性和早期模式中定义的访问器属性(对象字面量,直接在对象上的属性描述符)有什么区别吗?

        (1) 和你之前使用的defineProperty 没有区别,没有。它与顶部的对象初始值设定项 (var obj = ...) 之间存在差异:foo 属性是可枚举,而 (1) 示例中的 length 属性和 @987654325 @ 在您的 Eloquent JavaScript 示例中不是(因为 defineProperty 的默认值是将其定义为不可枚举的;您可以通过添加 enumerable: true 来更改它)。

        (除了编​​码风格偏好之外,是否有客观原因不在构造函数中定义 getter 和 setter?)

        没有。不过,我会注意到,您的特定示例并不能从拥有自己的财产中受益;所以我可能会在V.prototype 上定义它。但是除了使用在原型上定义的东西的通常好处(共享、可重用性、动态性)之外,没有特别的理由更喜欢这样做。定义一次意味着更少的函数对象,但对象相当便宜。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-04-02
          • 2012-07-06
          • 2013-12-15
          • 1970-01-01
          • 1970-01-01
          • 2022-12-09
          • 2019-05-21
          相关资源
          最近更新 更多