【问题标题】:Inheritance with JavaScript Prototypes in a Modular System在模块化系统中继承 JavaScript 原型
【发布时间】:2017-01-10 11:54:59
【问题描述】:

我正在构建一个 JavaScript 应用程序,其中我有一个主要的 JS 对象,我将为这篇文章调用 App

App 对象有一个 modules 属性,该属性包含一组 Module 对象,其中模块名称作为 App.modules 上的对象属性名称。

module 是用户为我的应用贡献的附加组件,它将使用 Prototypes 扩展 CoreModule 对象。

App.modules 对象会像这样向对象添加新模块...

App.modules[moduleName] = module-object-instance;

所以如果注册了 1 个模块,我所描述的总共有 3 个对象....

  • 应用
  • 核心模块
  • userBuiltMOdule

在我的 App 代码中,我希望有一个 registerModule() 函数来执行此操作...

// this will create a new instance of "moduleName" and add it to this.modules[moduleName] object
// for example I am hardcoding the module name as theres 1 module now
registerModule: function(moduleName, moduleClass) {

    // create new instance of module
    this.modules[moduleName] = new bookmarksModule();

    // run moduleName.init() function from the main App 
    this.modules[moduleName].init();

    console.log('App.registerModulemoduleName) function ran and created new instance of '+moduleName+'object');
},

现在要从我的CoreModule 扩展一个用户模块用户模块的...

createModule: function(moduleObject){
    var moduleCoreInstance = Object.create(this);
    // add sub-modules properties and functions to CoreModule 
    Object.keys(moduleObject).forEach(function(key){
        moduleCoreInstance[key] = moduleObject[key];
    });
    return moduleCoreInstance;
},

现在我要创建一个用户模块...

var bookmarksModule = ModuleCore.createModule({
    name: 'bookmarks',
    init: function(){
        console.log('bookmarksModule init() function ran from App object '+this.name+')');
    }
});

bookmarksModule 现在有nameinit()registerSidebar() from the CoreModule


现在是我这个系统的问题...

在我的 App.registerMOdule()` 函数中我无法使用:

// create new instance of module
this.modules[moduleName] = new bookmarksModule();

这将给出如下错误:

Uncaught TypeError: bookmarksModule is not a constructor
    at App.registerModule (yuzulat.js:51)
    at App.init (yuzulat.js:43)

如果我用它来切换代码,它会起作用:

this.modules[moduleName] = bookmarksModule;

其中bookmarksModule 是调用var bookmarksModule = ModuleCore.createModule() 的用户模块

所以我的问题是,有没有办法像我现在一样从CoreModule 扩展,但允许我的App.registerModule() 创建用户模块的新实例?


下面是我的完整示例代码...

JSBin 演示 - http://jsbin.com/yuzulat/1/edit?js,console,output

var ModuleCore = {

    // add ModuleCore prototype functions to the new sub module as well as pass in the sub-modules properties and functions and return to 
    // the sub-module so the sub-modules prototype will have CoreModules properties and function and its own properties and function merged
    // into its prototype
    createModule: function(moduleObject){
        var moduleCoreInstance = Object.create(this);
        // add sub-modules properties and functions to CoreModule 
        Object.keys(moduleObject).forEach(function(key){
            moduleCoreInstance[key] = moduleObject[key];
        });
        return moduleCoreInstance;
    },


    registerSidebar: function(){
        console.log('registerSidebar(sidebar options for module '+this.name+')');
    }
};

var bookmarksModule = ModuleCore.createModule({
    name: 'bookmarks',
    init: function(){
        console.log('bookmarksModule init() function ran from App object '+this.name+')');
    }
});


(function() {
  function App() {
    this.settings = {};
    this.modules = {};
  };

  App.prototype = {

    // run registerModules
    init: function(bookmarksModule) {

      console.log('App.init() function ran');

      // call App.registerModule() and pass in bookmarksModule module name
      this.registerModule('bookmarksModule', bookmarksModule);
    },

    // this will create a new instance of "moduleName" and add it to this.modules[moduleName] object
    // for example I am hardcoding the module name as theres 1 module now
    registerModule: function(moduleName, moduleClass) {

      // create new instance of module
      this.modules[moduleName] = new bookmarksModule();
      //this.modules[moduleName] = moduleClass;

      // run moduleName.init() function from the main App 
      this.modules[moduleName].init();

      console.log('App.registerModulemoduleName) function ran and created new instance of moduleName object');
    },


    // itterate this.modules object and call this.initModules() function on each module object
    registerModules: function() {
      console.log('App.registerModules() function ran');
    }

  };

  window.App = App;

})();


// create new instance of App
var App = new App();
App.init(bookmarksModule);


// call App.registerModule() and pass in bookmarksModule module name
App.registerModule('bookmarksModule', bookmarksModule);

【问题讨论】:

  • this.modules[moduleName] = new bookmarksModule(); ? moduleClass 参数呢?
  • @Poster createModule 给出一个普通对象,new 与函数一起使用。
  • @procrastinator moduleClass 你是在问它在哪里还是说它创建了一个对象的实例?如果第一个moduleClass 与上面示例用户创建的模块中的var bookmarksModule = ModuleCore.createModule() 相同
  • @JasonDavis 我的意思是你有一个名为moduleClass 的参数并且你从不使用它。看起来很奇怪。
  • @procrastinator 在您发布此内容时更新了评论。只是从我正在试验的 2 个不同的演示中创建这篇文章

标签: javascript inheritance prototype


【解决方案1】:

与其让构造函数立即生成继承 coremodule 的模块,不如让用户创建一个简单的构造函数并为 App 创建一个 addModule 函数。

这个函数应该接受一个对象,让它继承coreModule并立即添加到模块列表中。

App = {
    // ...

    addModule: function(name, module) {
        // make module inherit coreModule
        this.modules[name] = module;
    },

    // ...
};

function MyModule() {
    // Stuff
}

App.addModule(new MyModule());

【讨论】:

  • 在我的App 中,我计划在用户模块上调用一个名为init() 的函数。在 init() 函数中,它们基本上可以在那里运行模块功能,并在那里调用模块对象和 CoreModule 对象中的其他函数和属性。如果我要像您的演示一样从App 内部扩展模块,他们是否仍然能够访问模块代码中的CoreModule 函数,因为它是事后添加的,还是会按预期工作?
  • 我会测试它。在过去的几个月里,我尝试了一百万种不同的module 模式来尝试构建一个模块系统,其中Appmodule 可以相互访问
  • 还要在App.addModule() 中扩展CoreModule,我是否只需创建一个CoreModule 的新实例,然后将两者的原型与this.modules[name] = $.extend(CoreModule.prototype, module.prototype); 之类的东西合并
猜你喜欢
  • 2016-08-06
  • 2010-09-28
  • 2018-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多