为什么我们需要在JavaScript

问题描述:

定义构造函数

我读这段代码为什么我们需要在JavaScript

// Shape - superclass 
function Shape() { 
    this.x = 0; 
    this.y = 0; 
} 

// superclass method 
Shape.prototype.move = function(x, y) { 
    this.x += x; 
    this.y += y; 
    console.info('Shape moved.'); 
}; 

// Rectangle - subclass 
function Rectangle() { 
    Shape.call(this); // call super constructor. 
} 

// subclass extends superclass 
Rectangle.prototype = Object.create(Shape.prototype); 
Rectangle.prototype.constructor = Rectangle; 

var rect = new Rectangle(); 

rect instanceof Rectangle; // true 
rect instanceof Shape; // true 

rect.move(1, 1); // Outputs, 'Shape moved.' 

我真是被这个片段迷惑

Rectangle.prototype = Object.create(Shape.prototype); 
Rectangle.prototype.constructor = Rectangle; 

为什么我们不使用Rectangle.prototype =形状。原型,Object.create()有什么特别之处? 以及如果Rectangle.prototype.constructor = Rectangle;不叫?

+0

'为什么我们不使用Rectangle.prototype = Shape.prototype'矩形是一个形状,但不是每个形状都是矩形。改变Rectangle.prototype会改变Shape.prototype。如果有人想要使用它(和Chrome中的控制台日志记录),构造函数会进行一致性修复。更多关于构造函数,原型,继承,混合ins等在这里:http://stackoverflow.com/a/16063711/1641941 – HMR 2014-12-05 02:40:27

如果你做Rectangle.prototype = Shape.prototype那么你将在Rectangle.prototoype上执行的任何修改将反映在Shape.prototype上,因为它们是相同的对象。

为了避免这种情况,我们使用Object.create(Shape.prototype)创建一个新对象,该对象的原型链接指向Shape.prototype

至于Rectangle.prototype.constructor = Rectangle;,这是为了确保new Shape().constructor指向Rectangle而不是Shape

函数的原生prototype具有指向该函数的constructor属性。

例如

function Rectangle() {} 

Rectangle.prototype.constructor === Rectangle; //true 

现在,当我们做Rectangle.prototype = ...,我们打破参考,并需要事后修复。

+0

嗨,谢谢你的回复。是的..我总是困惑在什么情况下变量是一个参考(如在这种情况下Rectangle.prototype),当它是一个副本。你对此有何看法?或者你能指点我一些好的文章吗? – Blake 2014-12-04 22:39:19

+0

@Blake对象被引用,但原始值被复制(没有选择,因为它们是不可变的)。 – plalx 2014-12-04 22:49:51

如果您只是将Rectangle.prototype设置为Shape.prototype,那么RectangleShape将与原型共享同一个对象。这意味着,您添加到Rectangle.prototype的所有内容也可在Shape.prototype上获得 - Rectangle将不再继承自Shape

Object.create(parent)创建一个从传入的父对象继承的子对象。这样,父对象的所有属性也可用于子对象,而子对象的属性不会影响父对象。

要回答你的问题(“为什么我们需要在JavaScript中定义构造函数?”) - 我们不需要。您也可以使用普通对象:

// Shape - superclass 
function Shape() { 
    return { 
    x: 0, 
    y: 0, 
    // superclass method 
    move: function(x, y) { 
     this.x += x; 
     this.y += y; 
     console.info('Shape moved.'); 
    } 
    }; 
} 

// Rectangle - subclass 
function Rectangle() { 
    var rectangle = Shape(); 
    // rectangle-specific things could be added here 
    return rectangle; 
} 

var rect = Rectangle(); 

rect instanceof Rectangle; // false, instanceof does not work here 
rect instanceof Shape; // false 

rect.move(1, 1); // Outputs, 'Shape moved.' 
+0

你的非构造函数样本不太纯粹,而且很具误导性。以下是你应该做的事情'var shape = {...}; var rectangle = Object.create(shape); //添加矩形东西var r1 = Object.create(rectangle);' – plalx 2014-12-04 22:17:24

+0

请原谅我编写不太纯的示例。我只是想证明我们不受JavaScript中“类的”继承的束缚。纯净不是我最关心的问题。不过,我不同意这个例子有误导性。 Shape()在每次调用时都会返回一个新形状。通过'Object.create()'继承它没有任何好处。直接扩展该对象是完全可能的和安全的。 – 2014-12-04 22:22:18

+0

好吧,这是误导性的,因为有一个广泛的命名约定,它说上层函数应该是构造函数,但即使你修正了这个问题,你的代码在内存方面仍然效率低下,因为你没有通过原型分享任何东西。在执行方面也是低效的,例如,您将不得不每次创建新创建的形状对象以创建矩形实例。所有这些都通过像我建议的那样使用Object.create来解决,这是避免构造函数的标准方法。 – plalx 2014-12-04 22:48:34