【问题标题】:JS: struggling with prototypical inheritance [duplicate]JS:与原型继承作斗争[重复]
【发布时间】:2015-12-07 06:28:02
【问题描述】:

我以为我已经用 JavaScript 找到了继承,直到这个让我陷入了循环。

我有这个 SuperController 作为 AMD 模块:

define([
        'underscore',
        '#allCollections'
    ],

    function ( _ , allCollections) {


        function SuperController() {

        }

        SuperController.prototype = {

            control: function (viewPath, viewOpts, routerOpts, cb) {

            },

            default: function (id) {
                alert('controller has not yet implemented a default route.')
            }
        };


        return new SuperController();

    });

然后我有一个我想从 SuperController 继承的控制器:

define(
    [
        'underscore',
        '#allCollections',
        '#allCSS',
        '#SuperController'
    ],

    function (_, allCollections, allCSS, SuperController) {


        function Controller() {

        }

        Controller.prototype = {

            jobs: function (id, changeViewCallback) {

                var viewPath = 'app/js/jsx/relViews/jobs/jobsView';
                var viewOpts = {};
                viewOpts.id = id;
                var routerOpts = {
                    useSidebar: true
                };

                SuperController.control(viewPath, viewOpts, routerOpts, changeViewCallback); // works!
                this.control(viewPath, viewOpts, routerOpts, changeViewCallback); // does *not* work
            },


            default: function (id) {
                console.log('default route implemented in controller.');
            }
        };

        _.extend(Controller.prototype, SuperController.prototype);

        return new Controller();
    });

由于某种原因,我不能这样做 - 控制器无权访问 SuperController 中的控制权。让它工作的唯一方法是直接调用 SuperController.control() 。有什么明显的我做错了吗?

【问题讨论】:

  • 继承失败的原因是“default”是JS中的保留字,不能作为函数名

标签: javascript requirejs


【解决方案1】:

在语句_.extend(Controller.prototype, SuperController.prototype); 中,标识符SuperController 表示由return new SuperController(); 语句在SuperController 模块的定义中创建的对象。

因此,SuperController.prototypeundefined。您只是误解了原型的工作原理。

只是不要返回new SuperController(),而是从您的模块定义中返回SuperController 构造函数(因为 具有prototype 属性)并且它将起作用。

我建议您阅读关于 JS 继承的众多指南和 SO 答案之一,这已经被覆盖了 10 亿次。祝你好运!

Link to an answer

Link to a good guide (哎呀,自从我上次检查以来已经修改,现在使用ES6语法)

【讨论】:

  • 是的,有道理..也许我可以做 SuperController.constructor.prototype?
  • 不,因为你覆盖了SuperController.prototype!当您创建一个函数时,比如说Foo,它带有一个prototype 对象,该对象具有constructor 属性,即该函数FooFoo.prototype.constructor === Foo 为真。但是,如果您覆盖 Foo.prototype(在您的情况下是这样做的),则 .constructor 属性将丢失。它不会被实例“重新获得”,因此 SuperController.constructor 再次未定义。以与创建它的构造函数相同的方式命名实例只是非常糟糕的做法
  • 另外,使用.constructor 属性,在任何上下文中,都在执行反射。如果您的程序需要反射,很可能它实际上并不需要它,而您只是在编写软件时失败了。对象的.constructor 属性的使用几乎为零!只需编写适当的惯用 JavaScript,以热爱所有神圣的事物!
  • 实际上@jrsala 我的继承方案失败的原因是因为 default 是 JS 中的保留字。我尝试了一切,但无法弄清楚出了什么问题:) 我有点发疯了。我知道原型问题,这不是问题所在。
  • @AlexMills 当然,您对_.extend 的调用会覆盖您刚刚在Controller.prototype 中定义的defaultSuperController.prototype 中的那个... 您必须先执行扩展,然后覆盖继承的方法:Controller.prototype = _.extend({}, SuperController.prototype);。或者你可以只使用正确的 JS 继承而不混合:Controller.prototype = Object.create(SuperController.prototype); 然后Controller.prototype.default = function () { ... };
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-02
  • 2013-01-16
  • 2014-06-13
  • 2021-04-30
  • 2021-03-22
  • 1970-01-01
  • 2021-01-15
相关资源
最近更新 更多