我应该在JavaScript中将什么连接到子原型属性
What should I connect to the child prototype property in JavaScript
很抱歉,但我真的不知道如何更准确地指定这个问题。在这个例子中可以看到最常见的继承方式:
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 = new Shape();
var rect = new Rectangle();
rect.move(2, 1);
我关心以下代码:
//subclass extends superclass
Rectangle.prototype = new Shape();
直接连接到父原型属性不是更好吗。
Rectangle.prototype = Shape.prototype;
据我所知,所有对象都是直接从Object继承的。他们的原型不是连接到Object的某个实例,而是连接到其原型属性?
在上述情况下,Shape.call(this(;将复制属性(或类似的东西(,并且我们只需要继承Shape.prototype中的so和so方法。或者可能是我缺少了什么?
我关心以下代码:
//subclass extends superclass Rectangle.prototype = new Shape();
您应该是,这是一种常见的模式,但不是很好的模式,因为您使用Shape
来创建原型,并使用来初始化实例。它应该这样做。(例如,考虑一下,如果需要提供Shape
参数,你会怎么做?创建Rectangle.prototype
时会使用什么参数?(
但您也不想要Rectangle.prototype = Shape.prototype
,因为这样您就无法向Rectangle.prototype
添加内容(因为它指向的是Shape.prototype
所指向的同一对象,所以您也可以将它们添加到Shape
实例中(。
因此,我们想要创建一个使用Shape.prototype
作为原型的新对象(例如,继承自Shape.prototype
(,就像通过new Shape
创建的对象一样,但不需要调用Shape
来创建它;然后使用该新对象作为CCD_ 12。
从ECMAScript5开始,我们可以使用Object.create
:
Rectangle.prototype = Object.create(Shape.prototype);
Object.create
创建一个新对象,并将您给它的第一个参数指定为对象的底层原型。
这样做后,尽管严格意义上不需要,但我们也应该在新对象上设置constructor
属性,使其引用Rectangle
:
Rectangle.prototype.constructor = Rectangle;
我们这样做是因为这样,Rectangle.prototype
和Rectangle
之间的关系看起来就像规范的§13.2所说的那样。基本上,如果您有一个构造函数X
,那么X.prototype.constructor
应该引用X
。有时,人们会依赖它来进行克隆操作等等(JavaScript本身而不是依赖它——例如,instanceof
不依赖它(。
因此,我们可以使用ES5的Object.create
来实现这一点。但即使在今天,并不是所有的JavaScript引擎都支持Object.create
。因此,我们可以间接地做到这一点,方法是创建一个临时构造函数,让它借用Shape.prototype
作为其prototype
属性,然后使用该临时构造函数创建我们的新对象,用作Rectangle.prototype
:
function Ctor() { }
Ctor.prototype = Shape.prototype; // Borrow the prototype
Rectangle.prototype = new Ctor(); // Create the new object
我们应该再次设置constructor
属性:
Rectangle.prototype.constructor = Rectangle;
通常,不是每次都写出来,而是使用这样的助手:
function derive(Parent, Child) {
function Ctor() { this.constructor = Child; }
Ctor.prototype = Parent.prototype;
Child.prototype = new Ctor();
return Child; // For chaining
}
然后这样使用:
derive(Shape, Rectangle);
所有这些的最终结果是,我们只从Rectangle
中调用Shape
来初始化实例。我们不称之为创建Rectangle.prototype
。
如果您对JavaScript中的继承管道感兴趣,您可能会对我的Lineage
脚本感兴趣,该脚本处理以上内容以及更多内容。当我说";感兴趣;我不一定是说要使用它(尽管欢迎您使用(,但查看未经优化的源代码,并在本页中将Lineage
与在没有助手的情况下做同样的事情进行比较,可以让您了解这些东西是如何工作的。
JavaScript是一种原型的面向对象编程语言。也就是说,对象继承自其他对象。
JavaScript中的对象有一个特殊的[[proto]]
属性,它指向该对象的原型。此属性由JavaScript引擎内部维护,每个对象都有一个链接的原型链。例如:
null
^
| [[proto]]
|
+------------------+
| Object.prototype |
+------------------+
^
| [[proto]]
|
+------------------+
| Shape.prototype |
+------------------+
^
| [[proto]]
|
+---------------------+
| Rectangle.prototype |
+---------------------+
^
| [[proto]]
|
+------+
| rect |
+------+
当您编写Rectangle.prototype = new Shape();
时,您的原型链如上所示。请注意,实现这一点的新方法是Rectangle.prototype = Object.create(Shape.prototype);
。
null
^
| [[proto]]
|
+------------------+
| Object.prototype |
+------------------+
^
| [[proto]]
|
+---------------------+
| Rectangle.prototype |
| / Shape.prototype |
+---------------------+
^
| [[proto]]
|
+------+
| rect |
+------+
如果您编写Rectangle.prototype = Shape.prototype;
,那么您的原型链将如上所示。由于Rectangle.prototype
与Shape.prototype
相同,您将只继承一个原型,而不是两个原型。这意味着您不能将特定于Rectangle
的方法添加到Rectangle.prototype
中。
您应该选择哪种方法我更喜欢使用第一种方法,因为我们有两个单独的原型。您可以将特定于Rectangle
的方法添加到Rectangle.prototype
中。此外,它实际上是在扩展原型。在第二种情况下,根本没有继承。
这就是我现在通常写代码的方式:
function defclass(type, body) {
var neo = function () {
var self = new constructor;
return prototype.hasOwnProperty("constructor") &&
prototype.constructor.apply(self, arguments), self;
};
var constructor = function () {}; constructor.prototype = type;
var prototype = constructor.prototype = new constructor; prototype.new = neo;
return body.call(prototype, type), prototype;
}
使用defclass
,您现在可以创建如下类:
var shape = defclass(null, function () {
this.constructor = function () {
this.x = 0;
this.y = 0;
};
this.move = function (x, y) {
this.x += x;
this.y += y;
console.info("Shape moved.");
};
});
var rectangle = defclass(shape, function (shape) {
this.constructor = function () {
shape.constructor.call(this);
};
});
最后,您可以创建类的实例,如下所示:
var rect = rectangle.new();
rect.move(2, 1);
亲自观看演示:http://jsfiddle.net/VHfBd/1
链接:
- JavaScript中的对象继承
- 如何实现类声明上的伪古典继承权
- 为什么原型继承很重要
- 附加到原型属性的Do函数没有闭包
- 日期原型属性
- JS构造函数的原型属性与其原型之间的区别
- 为什么函数对象的实例没有继承函数原型属性
- 为什么浏览器显示原型属性不同
- 为什么在Function.prototype上没有原型属性
- 函数的原型属性
- 原型继承和原型属性
- 在JavaScript中,函数的默认值是多少'的原型属性
- Chrome 不支持 Javascript 中的原型属性吗?
- 我应该在JavaScript中将什么连接到子原型属性
- 更新 JavaScript 中的原型属性
- 请解释有关 JavaScript 中的原型属性和函数构造函数的详细信息
- 为什么原型函数无法读取原型属性
- 与对象属性同名的原型属性
- 如何获取原型属性列表
- 构造函数中的方法与函数的原型属性之间的差异
- JavaScript 原型属性
- 函数对象__proto__和原型属性
- 未在自定义 OL3 控件的构造函数中定义的原型属性