Javascript 特定对象实例的自定义函数-我有什么可能性?

Javascript 特定对象实例的自定义函数-我有什么可能性?,javascript,jquery,oop,handlebars.js,javascript-objects,Javascript,Jquery,Oop,Handlebars.js,Javascript Objects,因此,我目前正在构建一个相当大的框架,用于许多web项目。我很想得到以下场景的一些建议或最佳实践 我在一个web应用程序中有不同的章节。一次只能看到一个章节 第一次访问章节时调用函数createView()。它通过把手模板创建视图,插入XML文档中的所有副本(每种语言都有一个XML),并通过start()函数开始本章start()。它只是将视图插入DOM中,并启用所有功能,如单击事件、其他模块(图库、滑块等)等等 var Chapter = function(name) { this.n

因此,我目前正在构建一个相当大的框架,用于许多web项目。我很想得到以下场景的一些建议或最佳实践

我在一个web应用程序中有不同的章节。一次只能看到一个章节

第一次访问章节时调用函数
createView()
。它通过把手模板创建视图,插入XML文档中的所有副本(每种语言都有一个XML),并通过
start()
函数开始本章<每次再次访问章节时,都会调用code>start()。它只是将视图插入DOM中,并启用所有功能,如单击事件、其他模块(图库、滑块等)等等

var Chapter = function(name) {
    this.name = name;
    this.createView();
};

Chapter.prototype.createView = function() {
    var self = this;
    
    // get handlebars template
    this.template = config.app.getTemplate('chapters/'+self.name).then(function(hbs) {
        
        // compile hbs template, insert data here - if there is any
        var html = hbs();
        
        // save jQuery collection of HTML as view
        self.view = $(html);
        
        // insert copy from XML doc
        self.view.find('[data-text]').each(function() {
            var theID = '#'+$(this).attr('data-text');
            var theText = config.xml.find(theID).text();
            $(this).html(theText);
        });
        
        // start the experience
        self.start();
        
    });
};

Chapter.prototype.start = function() {
    
    // stop active experience
    if(config.experiences.active) {
        config.experiences.active.stop();
    }
    
    // scroll to top
    $(window).scrollTop(0);
    
    // save this chapter as the active one
    config.experiences.active = this;
    
    // insert view into DOM
    this.view.appendTo($('main'));
    
    // enable functionality
    this.initModules();
    this.initNavigation();
    this.initLocking();
    
};
现在,
Chapter
的每个实例都需要一些自定义函数,因为每个章节在许多项目中看起来都不同。但我不确定这是否是最好的方法:

initCustoms
中使用if-else的lof。 那么,添加一堆if-else语句真的是一种方法吗?似乎是这样。。。肮脏的。 我还想到:

为自定义章节创建对象并继承其原型 但这只会导致继承、更改其他实例或主
章节
原型方面的问题。我不想将
FireAndIce
的所有功能复制到实例中,基于我对该主题的研究,我无法正确地将原型(
FireAndIce
)继承到另一个原型(
章节
)的实例中

另外,出于好奇,以下是一个坏主意吗

通过jQuery创建一个自定义
start
事件,我可以将任意多个自定义处理程序绑定到该事件 撇开我做这件事的原因不谈,有什么问题吗?我有点喜欢为每个章节设置一个
开始
停止
事件的想法,我可以从任何地方绑定额外的功能

提前感谢您的建议。

有几个选项:

只需给它们分配一个函数 听起来好像只有几个
章节
实例,而且每个章节都是一次性的(例如,
FireAndIce
章节只有一个副本)。在这种情况下,您只需创建章节实例,然后在创建它们之后分配它们的
initCustoms
函数:

var fireAndIce = new Chapter();
fireAndIce.initCustoms = function() {
    // stuff for Fire and Ice
};
var secondSons = new Chapter();
secondSons.initCustoms = function() {
    // stuff for Second Sons
};
// ...
使用原型继承和构造函数 但是,如果您想通过继承实现这一点,下面是它的外观:

function Chapter() {
}
Chapter.prototype.setup = function() {
    // ...chapter common stuff
};

function FireAndIce() {
    Chapter.apply(this, arguments); // Chain to parent constructor
    // ...fire and ice stuff
}
FireAndIce.prototype = Object.create(Chapter.prototype);
FireAndIce.prototype.constructor = FireAndIce
FireAndIce.prototype.initCustoms = function() {
    // ...Fire and Ice custom stuff
};

function SecondSons() {
    Chapter.apply(this, arguments); // Chain to parent constructor
    // ...Second Sons stuff
}
SecondSons.prototype = Object.create(Chapter.prototype);
SecondSons.prototype.constructor = SecondSons
SecondSons.prototype.initCustoms = function() {
    // ...Second Sons custom stuff
};
这样,
FireAndIce
实例在其原型上共享
initCustoms
,并且也共享
章节
原型上的所有内容,因为
章节.prototype
FireAndIce.prototype
对象背后的原型。(对于
次级子公司也类似)

请注意,如果派生函数(
FireAndIce
SecondSons
)和
Chapter
具有不同的参数列表,而不是将所有参数从派生函数传递到
Chapter
,则只需传递适当的参数即可:

Chapter.call(this, the, appropriate, args, go, here);
使用不带构造函数的原型继承 有些人喜欢使用没有构造函数的原型继承,因此不使用
new
。这也是一种选择:

var ChapterProto = {
    setup: function() {
        // ...common chapter stuff...
    }
};
function createChapter() {
    var rv = Object.create(ChapterProto);
    // ...common chapter stuff...
    return rv;
}

var FireAndIceProto = Object.create(ChapterProto);
FireAndIceProto.initCustoms = function() {
    // ...Fire and Ice custom stuff...
};
function createFireAndIce() {
    var rv = Object.create(FireAndIceProto);
    createChapter.apply(rv, arguments);
    // ...Fire and Ice stuff...
    return rv;
}

var SecondSonsProto = Object.create(SecondSonsProto);
SecondSonsProto.initCustoms = function() {
    // ...Second Sons custom stuff...
};
function createSecondSons() {
    var rv = Object.create(SecondSonsProto);
    createChapter.apply(rv, arguments);
    // ...Second Sons stuff...
    return rv;
}
同样,如果参数列表不同,可以使用
.call
而不是
.apply

结论 对于一些对象,我更喜欢在创建实例之后将函数分配给它们。代码更少,更简单

但是对于对象类(在小写意义上),我会像上面那样使用带有构造函数的原型继承(但是其他一些人会在没有构造函数的情况下使用它)


上面使用了
Object.create
,这是ES5的新功能(现在大约有五年了)。如果您需要支持非常旧的引擎,可以多填充上面使用的一个参数版本(第二个参数不能在ES3引擎上多填充):


“但这只会导致继承、更改其他实例或主
章节
原型
”不,不会,不是您发布的代码。它在*instance
上创建了一个
prototype
属性,该属性与
章节`函数的
prototype
属性或通过
新章节
创建的原型基础实例完全无关。是的,我选择了一个糟糕的示例。它创建了一个
prototype
属性,但我希望
FireAndIce
的方法成为实例
\uuuuuuuuuuuu
的一部分。为清晰起见进行了编辑。可能混入可以工作,但如果某些函数仅用于一个实例,则可以在FireAndIce中定义函数并执行FireAndIce。调用(此)使该实例具有这些函数。以下内容可能会有所帮助,因为它包含了一个混合模式,并解释了如何使用call:感谢您的详细回复。真的很感激!我喜欢您的第一种方法,但是
章节
的实例不是单独创建的。每当调用另一个章节时,它们都会在循环中创建。想象一下,开发人员将使用这个框架来创建一本虚拟书。因此:我需要一种方法,让其他开发人员通过自定义功能“钩住”
章节,我尝试在这里提供一种方法。因此,在创建
章节
的实例后,我无法声明自定义函数,因为我不知道会有什么实例。您的第二种和第三种方法是我最初想到的。问题是:
章节
的一个实例已经并始终存在。现在,其中一些实例将需要自定义功能。所以这并不是说我可以用不同的原型/构造器重新创建章节。我需要以某种方式包含/导入来自定制原型(由其他人制作)的所有方法,以便
function Chapter() {
}
Chapter.prototype.setup = function() {
    // ...chapter common stuff
};

function FireAndIce() {
    Chapter.apply(this, arguments); // Chain to parent constructor
    // ...fire and ice stuff
}
FireAndIce.prototype = Object.create(Chapter.prototype);
FireAndIce.prototype.constructor = FireAndIce
FireAndIce.prototype.initCustoms = function() {
    // ...Fire and Ice custom stuff
};

function SecondSons() {
    Chapter.apply(this, arguments); // Chain to parent constructor
    // ...Second Sons stuff
}
SecondSons.prototype = Object.create(Chapter.prototype);
SecondSons.prototype.constructor = SecondSons
SecondSons.prototype.initCustoms = function() {
    // ...Second Sons custom stuff
};
Chapter.call(this, the, appropriate, args, go, here);
var ChapterProto = {
    setup: function() {
        // ...common chapter stuff...
    }
};
function createChapter() {
    var rv = Object.create(ChapterProto);
    // ...common chapter stuff...
    return rv;
}

var FireAndIceProto = Object.create(ChapterProto);
FireAndIceProto.initCustoms = function() {
    // ...Fire and Ice custom stuff...
};
function createFireAndIce() {
    var rv = Object.create(FireAndIceProto);
    createChapter.apply(rv, arguments);
    // ...Fire and Ice stuff...
    return rv;
}

var SecondSonsProto = Object.create(SecondSonsProto);
SecondSonsProto.initCustoms = function() {
    // ...Second Sons custom stuff...
};
function createSecondSons() {
    var rv = Object.create(SecondSonsProto);
    createChapter.apply(rv, arguments);
    // ...Second Sons stuff...
    return rv;
}
if (!Object.create) {
    Object.create = function(proto, props) {
        if (props) {
            throw "The second argument to Object.create cannot be polyfilled.";
        }

        function ctor() {
        }
        ctor.prototype = proto;
        return new ctor();
    };
}