【发布时间】:2018-07-14 19:33:58
【问题描述】:
我正在阅读 this article 关于 Javascript 中的超级方法。在最底部,作者使用了一种方法,它本质上是为每个方法函数对象添加一个 name 属性,并使用它在当前调用 super 的对象的原型链上找到匹配的方法。
我将复制下面的code:
var Base = function() {};
// Use the regular Backbone extend, but tag methods with their name
Base.extend = function() {
var Subclass = Backbone.Model.extend.apply(this, arguments);
_.each(Subclass.prototype, function(value, name) {
if (_.isFunction(value)) {
value._methodName = name;
}
});
return Subclass;
};
// Define a special `super` property that locates the super implementation of the caller
Object.defineProperty(Base.prototype, "super", {
get: function get() {
var impl = get.caller,
name = impl._methodName,
foundImpl = this[name] === impl,
proto = this;
while (proto = Object.getPrototypeOf(proto)) {
if (!proto[name]) {
break;
} else if (proto[name] === impl) {
foundImpl = true;
} else if (foundImpl) {
return proto[name];
}
}
if (!foundImpl) throw "`super` may not be called outside a method implementation";
}
});
它使用了Underscore.js和Backbone.js,我不是很熟悉,但是它们的用法不是问题所在。
设置super 属性getter 时,声明了4 个变量:impl、name、foundImpl 和proto。
impl持有调用super的方法,通过get.caller获得。 name 是调用super 的方法的名称(或者undefined,如果super 不是从方法中调用的)。 proto 保存着调用方法的对象,它的原型链将被遍历,直到我们找到超级方法。
现在foundImpl 让我有点困惑。它是一个布尔值,最初被赋值为this[name] === impl。由于this 指向调用方法的对象,this[name] 将返回方法本身,即=== 到impl。每次都是这样,除非name 是undefined(我们在方法外调用super)。
然后while(proto = Object.getPrototypeOf(proto)) 行开始遍历调用对象的原型链,从直接父级开始,直到到达null。
if(!proto[name]) 检查当前原型中是否存在同名方法。如果没有,它会跳出循环并且如果foundImpl 为假,则会引发错误。如前所述,我可以看到这种情况发生的唯一情况是如果在方法外部调用super,其中name 将是undefined,因此this[name] === impl 也将是错误的。否则,因为foundImpl 从一开始就已经为真了。
else if (proto[name] === impl) 将检查当前同名的原型方法是否严格等于调用super 的方法。老实说,我想不出这种情况是正确的,因为要从方法调用super,它必须被覆盖,从而生成两个不同的函数对象。例如:
var a = { method: function(){ return "Hello!"; } };
var b = Object.create(a);
console.log(a.method === b.method); //true
b.method = function(){ return "Hello World!"; };
console.log(a.method === b.method); //false
也许这毕竟只是一个安全检查,永远不会达到这个条件?
最后,else if (foundImpl) 将检查 foundImpl 是否为真(它很可能在第一次循环迭代中,除了上述特殊情况)并返回当前的 proto[name] 方法(如果是)。
所以我怀疑第二个条件的意义是什么:else if (proto[name] === impl)?它涵盖什么情况? foundImpl到底有什么作用?
【问题讨论】:
标签: javascript inheritance super