在功能继承模式中,Crockford通过以下方法引入了新的superior
方法:
Object.method('superior', function (name) {
var that = this,
method = that[name];
return function () {
return method.apply(that, arguments);
};
});
method
的位置:
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
示例:
var coolcat = function (spec) {
var that = cat(spec),
super_get_name = that.superior('get_name');
that.get_name = function (n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
};
我的问题是为什么不将that.get_name
分配给super_get_name
?
答案 0 :(得分:7)
“我的问题是为什么不将
that.get_name
分配给super_get_name
?”
因为get_name
方法将this
值设置为that
对象的方式是将其调用为:
that.get_name();
当一个函数作为一个对象的方法被调用时,该对象在该函数的调用中变为this
的值。
如果您这样做了:
var super_get_name = that.get_name;
super_get_name();
现在你正在调用一个分离的函数,因此它不知道它的this
值应该是什么,因此它使用默认值,通常是window
对象。
我不喜欢crockford显示的解决方案。通常,在这种情况下,您只需在此处创建一个新功能,而不是依靠Object.prototype
的扩展程序为您执行此操作。 (扩展Object.prototype
是非常难看的IMO。)
var coolcat = function (spec) {
var that = cat(spec),
_original_get_name = that.get_name,
super_get_name = function() {
return _original_get_name.apply(that, arguments);
};
that.get_name = function (n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
};
或者在现代实现中,您使用Function.prototype.bind
创建一个新函数,其this
值绑定到您作为.bind()
的第一个参数提供的任何值。
var coolcat = function (spec) {
var that = cat(spec),
super_get_name = that.get_name.bind(that);
that.get_name = function (n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
};
答案 1 :(得分:2)
在Crockford的功能继承模式意义上,引用基类方法是完全有效的
var super_get_name = that.get_name;
这就是Crockford在lecture JavaScript Master Class中教授它的方法,请参阅功能继承部分。
稍后 - 派生类可能会覆盖该方法 - 您只需调用它
super_get_name();
Crockford的superior
方法在功能继承模式中毫无意义。
因为在我看来,生产者函数定义的方法中 this
永远不需要。如果您在方法中使用this
,那么由于this
的动态范围和操作,您将遇到各种麻烦:
function mammal(spec){
var that = {};
that.legs = Math.round(Math.random() * 4);
that.get_name = function(){
return spec.name + "with" + that.legs; // always use that not this
};
that.isProperThis = function(){
console.log( this === that );
};
return that;
};
var myMammal = mammal({name: 'Herb'});
myMammal.isProperThis(); // true
myMammal.isProperThis.call(window); // false
setTimeout(myMammal.isProperThis, 1); // false
如果您坚持在方法中使用this
,则不能再将它们视为JavaScript中的“一等”变量。相反,您必须通过调用bind
将其转换为“活页夹”,如本文第一个答案中所述。
答案 2 :(得分:0)
superior
是Object构造函数原型中定义的方法。它缓存了一个对象的方法,因此即使以后更改它也会返回原始方法。
来自JavaScript:好的部分,第54页:
即使属性发生了变化,该函数也会调用原始方法。
答案 3 :(得分:0)
cookie怪物给出的答案是正确的,但我想补充说明。
正如cookie怪说的那样,如果你写的话
var super_get_name = that.get_name;
调用 super_get_name 将不再将任何值绑定到此,使其成为未绑定的函数。
然而,在Crockford在 The Good Parts 中给出的示例中,如果 super_get_name 通过以您建议的方式编写而未绑定,则无关紧要,因为此永远不会在其调用中使用。
你最终会做以下事情:
super_get_name = function () {
return that.says() + ' ' + spec.name +
' ' + that.says();
(右操作数在分配给 cat 的函数的上下文中执行。)
我认为Crockford在这里避免使用未绑定的函数来演示一般原则,即使他的具体示例不需要绑定。