简体   繁体   English

基于Crockford的函数继承在Javascript中使用超级方法

[英]Using super methods in Javascript based on Crockford's functional inheritance

I've been reading the chapter on functional inheritance in Crockford's 'The Good Parts'. 我一直在阅读Crockford的“ The Good Parts”中有关函数继承的章节。 In the mammal example he gives I'm a bit confused as to why he uses the superior method to modify the get_name function. 在哺乳动物的示例中,对于他为什么使用superior方法修改get_name函数,他有些困惑。 Here is the example in question: 这是有问题的示例:

Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};

var mammal = function (spec) {
    var that = {};

    that.get_name = function () {
        return spec.name;
    };

    that.says = function () {
        return spec.saying || '';
    };

    return that;
};

var myMammal = mammal({
    name: 'Herb'
});

var cat = function (spec) {
    spec.saying = spec.saying || 'meow';
    var that = mammal(spec);

    that.purr = function (n) {
        var i, s = '';
        for (i = 0; i < n; i += 1) {
            if (s) {
                s += '-';
            }
            s += 'r';
        }
        return s;
    };

    that.get_name = function () {
        return that.says() + ' ' + spec.name + ' ' + that.says();
    };

    return that;
};

Object.method('superior', function (name) {
    var that = this,
        method = that[name];
    return function () {
        return method.apply(that, arguments);
    };
});

var coolcat = function (spec) {
    var that = cat(spec);
    var super_get_name = that.superior('get_name');

    that.get_name = function (n) {
        return 'like ' + super_get_name() + ' baby';
    };
    return that;
};

var myCoolCat = coolcat({
    name: 'Bix'
});

var name = myCoolCat.get_name(); // 'like meow Bix meow baby'

I'm confused about this because I can replicate the same thing by removing the superior method and just changing coolcat as follows: 我对此感到困惑,因为我可以通过删除superior方法并只需更改coolcat来复制相同的coolcat ,如下所示:

var coolcat = function(spec) {
    var that = cat(spec);
    var super_get_name = that.get_name();

    that.get_name = function(n) {
        return 'like ' + super_get_name + ' baby';
    };
    return that;
};

So, I don't understand why Crockford chooses to use the superior method. 因此,我不明白为什么Crockford选择使用superior方法。 Is anyone able to explain at all? 有人可以解释吗?

The idea here is that this: 这里的想法是这样的:

var super_get_name = that.superior('get_name');

makes super_get_name into a function that — every time it is called — invokes that 's original get_name method. 使super_get_name成为一个函数-每次调用时-都会调用that方法的原始 get_name方法。 This allows the new get_name to call the old (super-class) get_name . 这允许新的 get_name调用旧的 (超类) get_name

Now, if the original get_name method will never have any effect other than to return a single value that never changes, then yeah, this is kind of pointless; 现在,如果原始的get_name方法除了返回一个永远不变的值之外,将永远不会有任何其他效果,那么,是的,这毫无意义; you can just save that single-value-that-never-changes and then use it in the new get_name . 您可以只保存该单值永不更改,然后在新的get_name使用它。 But if the original get_name can actually do things (such as, say, run an AJAX request, or change the styling of an HTML element), or if its return-value can change (say, if there were some corresponding set_name method), then there would be an important difference between what your code does (save the original return-value and use it) and what Crockford's code does (save the original method and invoke it). 但是,如果原始的get_name实际上可以执行操作(例如,运行AJAX请求或更改HTML元素的样式),或者其返回值可以更改(例如,是否有一些对应的set_name方法),那么您的代码做什么(保存原始返回值并使用它)和Crockford的代码做什么(保存原始方法并调用它)之间将存在重要的区别。

The confusion that arises from this chapter of Crockford's book arises as what Crockford describes is "his" preferred pattern for implementing inheritance in JavaScript, which relies on his extending the Function object with the Function.prototype.method (chapter 1.3) which he uses to add methods to the Function object. Crockford在本书的这一章中引起了困惑,因为Crockford所描述的是“他的”在JavaScript中实现继承的首选模式,这取决于他用Function.prototype.method (第1.3章)扩展的Function对象,向Function对象添加方法。

The problem addressed in the coolcat example is the need to access the method of the parent type. coolcat示例中解决的问题是需要访问父类型的方法。 In 'classical' OO languages like Java this is natural as classes exist in their own right. 在像Java这样的“经典” OO语言中,这很自然,因为类本身就存在。 In JavaScript inheritance is prototypical, you make an object of type mammal and then modify the object to create the type cat or coolcat . 在JavaScript继承是典型的情况下,您将创建一个mammal类型的对象,然后修改该对象以创建类型catcoolcat

Depending on your design you may add properties and functions or override an 'inherited' function. 根据您的设计,您可以添加属性和功能或覆盖“继承的”功能。 The problem arises when you override an 'inherited' function, in JavaScript you basically replace the old function with the new function, thereby loosing the older function. 当您覆盖“继承的”函数时,就会出现问题,在JavaScript中,您基本上用新函数替换了旧函数,从而失去了旧函数。

Crockford now needs to do two things: 克罗克福德现在需要做两件事:

  1. get the parent's (cat's) get_name method; 获取父(猫)的get_name方法; and
  2. save it in a manner that can be used from within the overridden method. 以一种可以从覆盖方法中使用的方式保存它。

In this code: 在此代码中:

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

He does 1. by calling the superior method to get a function that gets the cat's get_name function; 他通过调用高级方法来获得一个函数,该函数获得了猫的get_name函数。 and he does 2. by saving it to the super_get_name variable within the coolcat function(/object) allowing access to the cat's get_name function before it is overridden (more correctly overwritten) by the coolcat's get_name function. 然后他通过将其保存到coolcat函数(/ object)中的super_get_name变量中来进行操作,从而允许在猫被其猫的get_name函数覆盖(更正确地覆盖)之前访问该猫的get_name函数。

In my opinion the confusion arises because: 我认为之所以会引起混淆,是因为:

  1. The superior method is named oddly: the 'superior' method is simply a function look up by name method and could be better named, for example as getFunctionByName (you can try this by replacing the string get_name , by purr , the coolcat's get_name will now call purr, just remember to call it as super_get_name(10) otherwise you'll get an empty string back). superior方法的名称很奇怪:“ superior”方法只是按名称查找函数 ,可以更好地命名,例如,将其命名为getFunctionByName (您可以通过将字符串get_name替换为purr来尝试,coolcat的get_name现在会调用purr,只需记住将其称为super_get_name(10)否则将返回一个空字符串)。
  2. Secondly the code and the pattern obfuscates the code by relying on some particular Crockford patterns, and is likely to stresses you out if you attempt to dive into this chapter without having followed the entire book. 其次,代码和模式依赖于某些特定的Crockford模式来混淆代码,如果您在不遵循整本书的情况下尝试进入本章,可能会给您带来压力。

I think there is a simpler way to achieve this, one that I think because it is completely localized is easier to understand etc., as in the code below: 我认为有一种更简单的方法可以实现此目的,我认为因为它是完全本地化的,因此更易于理解等,如下面的代码所示:

var coolcat = function(spec) {
    var that = cat(spec);
    that.parent_get_name = that.get_name;
    that.get_name = function() {
       return 'like ' + this.parent_get_name() + ' baby';
    };
    return that;
};

There are some other oddities for example the argument n in definition of the coolcat get_name function, which I can only assume came from copying the purr function, which would suggest a ghost writer! 还有其他一些奇怪的地方,例如coolcat get_name函数的定义中的参数n ,我只能假定它来自复制purr函数,这可能表明是幽灵作家!

Finally, I would suggest that before one reads the book one should listen to his talk on 'JavaScript the good parts'. 最后,我建议在读本书之前,应该先听一下关于“ JavaScript的好部分”的演讲。 The talk is absolutely brilliant, much better than the book. 演讲绝对精彩,比这本书好得多。

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

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