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

时间:2014-11-14 11:59:26

标签: javascript jquery oop handlebars.js javascript-objects

因此,我正在构建一个非常大的框架,用于许多Web项目。我很乐意为以下场景提供一些建议或最佳实践。

我在网络应用中有不同的章节。一次只能看到一章。

第一次访问章节时调用函数createView()。它通过把手模板创建视图,插入XML文档中的所有副本(我们有每种语言的XML),并通过start()函数启动章节。每当再次访问章节时,都会调用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中使用lof of else。

Chapter.prototype.start = function() {
    ...
    this.initCustoms();
};

Chapter.prototype.initCustoms = function() {
    if(this.name === 'Fire and Ice') {
        // do abc
    } else if(this.name === 'Second Sons') {
        // do xyz
    }
};

那么添加一堆if-else语句真的要走了吗?看起来好像......很脏。 我也想说:

为自定义章节创建一个对象并继承其原型

var FireAndIce = function() {
    // do abc
}

FireAndIce.prototype = Chapter.prototype;
FireAndIce.prototype.constructor = Chapter;

Chapter.prototype.start = function() {
    ...
    this.initCustoms();
};

Chapter.prototype.initCustoms = function() {
    if(this.name === 'Fire and Ice') {
        // inherit functionality of FireAndIce. Can't post it here as I have not been able to do this properly.
    }
    ...
};

但这只会导致继承问题,更改其他实例或主Chapter原型。我不想将FireAndIce的所有功能复制到实例上,根据我对此主题的研究,我无法正确地从原型(FireAndIce)继承到另一个实例原型(Chapter)。

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

通过jQuery创建自定义start事件,我可以根据需要绑定多个自定义处理程序

Chapter.prototype.start = function() {
    ...
    this.initCustoms();
    this.trigger('start');
};

Chapter.prototype.initCustoms = function() {
    if(this.name === 'Fire and Ice') {
        this.on('start', function() {
            // do abc
        });
    }
    ...
};

撇开我为什么要这样做的原因,它有什么问题吗?我有点想为每个章节设置一个startstop事件,我可以从中处理其他功能。

提前感谢您的建议。

1 个答案:

答案 0 :(得分:1)

有两种选择:

只需为它们分配一个功能

听起来似乎只有少数Chapter个实例,并且每章都是一次性的(例如,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,并在Chapter原型上共享所有内容,因为Chapter.prototypeFireAndIce.prototype背后的原型1}}对象。 (同样适用于SecondSons。)

请注意,如果派生函数(FireAndIceSecondSons)和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

结论

对于少数几个对象,我宁愿在创建实例后只为它们分配函数。更少的代码,更简单。

但是对于对象的(在小写意义上),我使用原型继承和上面的构造函数(但是其他一些人在没有构造函数的情况下使用它)。 / p>


以上使用Object.create,这是ES5的新功能(现在大约五年)。如果你需要支持真正的旧引擎,你可以填充上面使用的单参数版本(第二个参数不能在ES3引擎上进行polyfilled):

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