简体   繁体   English

在javascript中修改原型时的超级功能

[英]Super function when modifying a prototype in javascript

当你在javascript中修改原型时,是否有像super这样的函数?

There is unfortunately no super keyword or equivalent in ECMAScript. 遗憾的是,ECMAScript中没有超级关键字或等价物。 This has been a major source of confusion and difficulty to implement real-life inheritance. 这是实现现实生活继承的主要困惑和难点。

Lot's of people have implemented complex solutions (Prototype library, John Resig, and many others), all these solutions create extra closures, manipulate functions code, use special names that may clash with upcoming standards changes, or other complex tricks. 很多人已经实现了复杂的解决方案(Prototype库,John Resig和许多其他解决方案),所有这些解决方案都创建了额外的闭包,操作函数代码,使用可能与即将发生的标准更改冲突的特殊名称,或其他复杂的技巧。 Some of these solutions just do not work if there is more than one level of inheritance ( A > B > C ) because these use some form of " this.super " that always refers to C's and therefore creates an infinite loop if B also attempts to call its super method (which happens in real code). 如果存在多个继承级别(A> B> C),这些解决方案中的某些解决方案不起作用,因为它们使用某种形式的“ this.super ”,它总是引用C,因此如果B也尝试,则会创建无限循环调用它的超级方法(在实际代码中发生)。

There exists however a very simple an much more efficient solution that I found and use successfully in my projects, and that works for any levels of inheritance, and does not run any risk of name collision. 然而,存在一个非常简单的更有效的解决方案,我在我的项目中成功找到并使用它,并且适用于任何级别的继承,并且不会冒任何名称冲突的风险。 No closure required, no magic, just simple straightforward JavaScript that works on all browsers, here it is: 不需要关闭,没有魔法,只是简单直接的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!
}

The only drawback of this solution is that it is requires to type a few more keystrokes than the other solutions. 此解决方案的唯一缺点是需要键入比其他解决方案更多的键击。 But because there are no closures involved, there is no unnecessary function calls so it will likely be more efficient than any other solution I have seen so far. 但是因为没有涉及闭包,所以没有不必要的函数调用,因此它可能比我迄今为止看到的任何其他解决方案更有效。

Alternatively, if you want to pass all arguments of draw() to the super class method, you can use this form: 或者,如果要将draw()的所有参数传递给超类方法,可以使用以下形式:

Shape.prototype.draw.apply( this, arguments );

Or if the parameters are known and differ from that of the super class you can use: 或者,如果参数已知并且与超类的参数不同,则可以使用:

Shape.prototype.draw.call( this, param1, param2 );

I hope this helps others :) 我希望这有助于其他人:)

Not in the language itself -- but there is no reason you cannot add it when you are creating your class. 不是语言本身 - 但是在创建课程时没有理由不能添加它。 There is actually a very nice exposition on the way that Coffeescript manages prototypal inheritance by Justin Reidy on his blog 对于Justin Reidy 在他的博客上 Coffeescript 管理原型继承的方式,实际上有一个非常好的阐述

The key part is reproduced here: 关键部分在这里转载:

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;
}

You will also probably want to read @bobince's introduction to working with classes in JavaScript . 您可能还想阅读@ bobince关于使用JavaScript中的类的介绍

not by default, but if you are looking for a way to do classical inheritance in javascript you could consider using a library like prototype or mootools ... or if you don't want to go that route, John Resig, the creator of jQuery provides a really nice light solution: 不是默认情况下,但是如果你正在寻找一种在javascript中进行经典继承的方法,你可以考虑使用像原型mootools这样的库......或者如果你不想走那条路,John Resig,jQuery的创建者提供了一个非常好的解决方案:

http://ejohn.org/blog/simple-javascript-inheritance/ http://ejohn.org/blog/simple-javascript-inheritance/

It's just important to note that inherited arrays and objects are not copied to instances with this implementation - so if you inherit an array you'll want to redifine its values in the subclasses constructor function (otherwise all instances will share a single array) - I can post an example for you if you want to see, there is also one in the comments of that post. 重要的是要注意,继承的数组和对象不会被复制到具有此实现的实例 - 所以如果你继承了一个数组,你需要在子类构造函数中重新定义它的值(否则所有实例将共享一个数组) - I如果你想看到,可以为你发一个例子,该帖子的评论中也有一个。

It's possible to use JavaScript's .caller facility to create a general solution that lets you invoke a superclass' implementation of a function with the same name as the calling function. 可以使用JavaScript的.caller工具创建一个通用解决方案,该解决方案允许您调用与调用函数同名的函数的超类实现。 The basic idea is to use a reference to the calling function, walk up the class hierarchy to find which class actually implements that function, and then go up one more step to get the super class. 基本思想是使用对调用函数的引用,向上遍历类层次结构以查找实际实现该函数的类,然后再向上一步以获取超类。

See https://gist.github.com/1265237 for an example. 有关示例,请参阅https://gist.github.com/1265237

This allows a call to a super function without needing to specify the name of the current class. 这允许调用超级函数,而无需指定当前类的名称。 Eg, if A is a superclass of B, then: 例如,如果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

The _super implementation in the above gist does more work the first time it's called, but speeds up in subsequent calls. 上面要点中的_super实现在第一次调用时会执行更多工作,但在后续调用中会加速。 This uses the JavaScript function .caller (and falls back to the older arguments.callee.caller in older browsers). 这使用JavaScript函数.caller(并在旧浏览器中回退到旧的arguments.callee.caller)。 It's widely claimed that callee/caller are slow because they can't be optimized, but "slow" is a relative term. 人们普遍声称被调用者/来电者很慢,因为他们无法进行优化,但“慢”是一个相对术语。 Depending on your use case, this approach might well suffice. 根据您的使用情况,这种方法可能就足够了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM