当您在javascript中修改原型时,是否有像super
这样的函数?
答案 0 :(得分:4)
很遗憾,ECMAScript中没有超级关键字或等效关键字。这是实现现实生活继承的一个主要困惑和难点。
许多人已经实现了复杂的解决方案(Prototype库,John Resig等等),所有这些解决方案都创建了额外的闭包,操作函数代码,使用可能与即将发生的标准更改冲突的特殊名称,或其他复杂的技巧。如果存在多个继承级别(A> B> C),则这些解决方案中的某些解决方案不起作用,因为它们使用某种形式的“ this.super ”,它始终引用C和因此,如果B也试图调用其超级方法(在实际代码中发生),则会创建一个无限循环。
然而,存在一个非常简单的更有效的解决方案,我在我的项目中成功找到并使用它,并且适用于任何级别的继承,并且不会冒任何名称冲突的风险。不需要关闭,没有魔法,只是简单直接的JavaScript适用于所有浏览器,这里是:
// Create base class
Shape = function() {};
// Add method draw() to base class
Shape.prototype.draw = function() {};
// Create new class
Box = function() {};
// Make Box inherit from base class using Douglas Crockford Object.create()
// that is now part of ECMAScript 5 (which is why I recommend it)
Box.prototype = Object.create( Shape.prototype );
// Reset the constructor property erased by the former statement
Box.prototype.constructor = Box;
// Create draw() method for Box that calls it's base class draw() method
Box.prototype.draw = function() {
Shape.prototype.draw.call( this ); // Here you go!
}
此解决方案的唯一缺点是需要键入比其他解决方案更多的键击。但是因为没有涉及闭包,所以没有不必要的函数调用,因此它可能比我到目前为止看到的任何其他解决方案更有效。
或者,如果要将draw()的所有参数传递给超类方法,可以使用以下形式:
Shape.prototype.draw.apply( this, arguments );
或者,如果参数是已知的并且与超类的参数不同,则可以使用:
Shape.prototype.draw.call( this, param1, param2 );
我希望这有助于其他人:)
答案 1 :(得分:2)
不是语言本身 - 但是在创建课程时没有理由不能添加它。实际上有一个非常很好的阐述了Coffeescript manages prototypal inheritance by Justin Reidy on his blog
的方式关键部分在此转载:
var __hasProp = Object.prototype.hasOwnProperty;
function __extends(child, parent) {
for (var key in parent) {
if (__hasProp.call(parent, key)) {
child[key] = parent[key];
}
}
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor;
child.__super__ = parent.prototype;
return child;
}
您可能还想阅读@bobince's introduction to working with classes in JavaScript。
答案 2 :(得分:1)
不是默认情况下,但如果您正在寻找一种在javascript中进行经典继承的方法,您可以考虑使用像prototype或mootools这样的库...或者如果您不想走这条路,jQuery的创建者John Resig提供了一个非常好的解决方案:
http://ejohn.org/blog/simple-javascript-inheritance/
重要的是要注意,继承的数组和对象不会复制到具有此实现的实例 - 因此,如果继承数组,则需要在子类构造函数中重新定义其值(否则所有实例将共享一个数组) - 如果你想看,我可以为你发一个例子,那篇文章的评论中也有一个。
答案 3 :(得分:1)
可以使用JavaScript的.caller工具创建一个通用解决方案,允许您调用与调用函数同名的函数的超类实现。基本思想是使用对调用函数的引用,向上遍历类层次结构以查找实际实现该函数的类,然后再向上一步以获取超类。
有关示例,请参阅https://gist.github.com/1265237。
这允许调用超级函数,而无需指定当前类的名称。例如,如果A是B的超类,那么:
A.prototype.calc = function ( x ) {
return x * 2;
}
B.prototype.calc = function ( x ) {
return this._super( x ) + 1;
}
var b = new B();
b.calc( 3 ); // = 7
上面要点中的_super实现在第一次调用时会有更多工作,但在后续调用中会加快速度。这使用JavaScript函数.caller(并在旧浏览器中回退到旧的arguments.callee.caller)。人们普遍声称被调用者/来电者很慢,因为他们无法进行优化,但“慢”是一个相对术语。根据您的使用情况,这种方法可能就足够了。