了解Crockford介绍的优越方法

时间:2014-01-24 12:07:50

标签: javascript javascript-objects

在功能继承模式中,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

4 个答案:

答案 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在这里避免使用未绑定的函数来演示一般原则,即使他的具体示例不需要绑定。