构造函数

时间:2016-04-15 06:01:11

标签: javascript oop design-patterns constructor

我已经看到通过对象文字和属性描述符中的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; }
});

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

在constuctor中使用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?)

3 个答案:

答案 0 :(得分:1)

  

上面构造函数中的(1)中定义的访问器属性是否存在差异,以及在早期模式中定义的访问器属性(对象文字,直接在对象上的属性描述符)?

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

  

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

没有。我会注意到,你的特定例子并不是从自己的财产中获益;所以我可能会在V.prototype上定义它。但除了使用在原型上定义的东西(共享,可重用性,动态性)的通常好处之外,没有特别的理由偏爱它。定义一次意味着更少的功能对象,但对象相当便宜。

答案 1 :(得分:0)

  

上面构造函数中的(1)中定义的访问器属性是否存在差异,以及在早期模式中定义的访问器属性(对象文字,直接在对象上的属性描述符)?

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

  

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

是的,取决于您的目的。

prototype

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

    每个实例的优点:

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

答案 2 :(得分:0)

当使用函数构造函数模式创建新的实例对象时,在创建的每个实例的代码中,您将具有一个作为函数的吸气剂(即另一个对象),因此您将为每个实例创建两个对象。相反,在将getter方法附加到原型的其他解决方案中,对于所有创建的对象,只有一个getter。此外,在对象文字表示法中,属性configurableenumerable默认情况下为true,而不是函数defineProperty,默认情况下为false,但您可以要解决此差异,请在V函数中显式设置这些属性,或者您可以按照以下方式进行操作:

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