Javascript 将JS单例转换为实例/ctor的策略

Javascript 将JS单例转换为实例/ctor的策略,javascript,durandal,Javascript,Durandal,下面是Durandal starter kit的一个样本,它返回了一个单件。我很好奇,最简单的方法是把它转换成一个实例,最好不要完全改变语法 define(['plugins/http', 'durandal/app', 'knockout', 'lodash'], function (http, app, ko, _) { var displayName = 'Flickr', images = k

下面是Durandal starter kit的一个样本,它返回了一个单件。我很好奇,最简单的方法是把它转换成一个实例,最好不要完全改变语法

define(['plugins/http', 'durandal/app', 'knockout', 'lodash'], function (http, app, ko, _) {
                var displayName = 'Flickr',
                                images = ko.observableArray([]),
                                activate = function () {
                                                //the router's activator calls this function and waits for it to complete before proceeding
                                                if (this.images().length > 0) {
                                                                return;
                                                }

                                                var that = this;
                                                return http.jsonp('http://api.flickr.com/services/feeds/photos_public.gne', { tags: 'mount ranier', tagmode: 'any', format: 'json' }, 'jsoncallback').then(function(response) {
                                                                that.images(response.items);
                                                });
                                },
                                select = function(item) {
                                                //the app model allows easy display of modal dialogs by passing a view model
                                                //views are usually located by convention, but you an specify it as well with viewUrl
                                                item.viewUrl = 'views/detail';
                                                app.showDialog(item);
                                },
                                somePrivate = function() { return ‘blah’; },
                                canDeactivate = function () {
                                                //the router's activator calls this function to see if it can leave the screen
                                                return app.showMessage('Are you sure you want to leave this page?', 'Navigate', ['Yes', 'No']);
                                };

                return {
                                displayName: displayName,
                                images: images,
                                activate: activate,
                                select: select,
                                canDeactivate: canDeactivate
                };
});
这是可行的,但添加“这”是一件痛苦的事情。到处都是,我也失去了上面的公共/私人区别:

define(['plugins/http', 'durandal/app', 'knockout', 'lodash'], function (http, app, ko, _) {
                var ctor = function() {
                                this.displayName = 'Flickr';
                                this.images = ko.observableArray([]);
                                this.activate = function () {
                                                //the router's activator calls this function and waits for it to complete before proceeding
                                                if (this.images().length > 0) {
                                                                return;
                                                }

                                                var that = this;
                                                return http.jsonp('http://api.flickr.com/services/feeds/photos_public.gne', { tags: 'mount ranier', tagmode: 'any', format: 'json' }, 'jsoncallback').then(function(response) {
                                                                that.images(response.items);
                                                });
                                };
                                this.select = function(item) {
                                                //the app model allows easy display of modal dialogs by passing a view model
                                                //views are usually located by convention, but you an specify it as well with viewUrl
                                                item.viewUrl = 'views/detail';
                                                app.showDialog(item);
                                };
                                this.canDeactivate = function () {
                                                //the router's activator calls this function to see if it can leave the screen
                                                return app.showMessage('Are you sure you want to leave this page?', 'Navigate', ['Yes', 'No']);
                                };
                };

    return ctor;
});
我想要下面这样的工作-有什么建议吗

define(['plugins/http', 'durandal/app', 'knockout', 'lodash'], function (http, app, ko, _) {
    var ctor = function() {
        var displayName = 'Flickr',
            images = ko.observableArray([]),
            activate = function () {
                //the router's activator calls this function and waits for it to complete before proceeding
                if (this.images().length > 0) {
                    return;
                }

                var that = this;
                return http.jsonp('http://api.flickr.com/services/feeds/photos_public.gne', { tags: 'mount ranier', tagmode: 'any', format: 'json' }, 'jsoncallback').then(function(response) {
                    that.images(response.items);
                });
            },
            select = function(item) {
                //the app model allows easy display of modal dialogs by passing a view model
                //views are usually located by convention, but you an specify it as well with viewUrl
                item.viewUrl = 'views/detail';
                app.showDialog(item);
            },
            canDeactivate = function () {
                //the router's activator calls this function to see if it can leave the screen
                return app.showMessage('Are you sure you want to leave this page?', 'Navigate', ['Yes', 'No']);
            };

        return {
            displayName: displayName,
            images: images,
            activate: activate,
            select: select,
            canDeactivate: canDeactivate
        };
    };

    return _.bind(ctor, this);
});

我也试过在变量前后在ctor中使用bindAll。

你试过让ctor成为一种生活吗?像这样:

define(['plugins/http', 'durandal/app', 'knockout', 'lodash'], function (http, app, ko, _) {
var ctor = (function() {
    var displayName = 'Flickr',
        images = ko.observableArray([]),
        activate = function () {
            //the router's activator calls this function and waits for it to complete before proceeding
            if (this.images().length > 0) {
                return;
            }

            var that = this;
            return http.jsonp('http://api.flickr.com/services/feeds/photos_public.gne', { tags: 'mount ranier', tagmode: 'any', format: 'json' }, 'jsoncallback').then(function(response) {
                that.images(response.items);
            });
        },
        select = function(item) {
            //the app model allows easy display of modal dialogs by passing a view model
            //views are usually located by convention, but you an specify it as well with viewUrl
            item.viewUrl = 'views/detail';
            app.showDialog(item);
        },
        canDeactivate = function () {
            //the router's activator calls this function to see if it can leave the screen
            return app.showMessage('Are you sure you want to leave this page?', 'Navigate', ['Yes', 'No']);
        };

    return {
        displayName: displayName,
        images: images,
        activate: activate,
        select: select,
        canDeactivate: canDeactivate
    };
}());

return ctor;
}))


这似乎与我想要的非常接近,而且几乎是直接翻译。

对不起,兄弟,你必须习惯这一点。您确定使用bind、extend或bindAll没有任何技巧可以帮助保持语法相似吗?这实际上与singleton相同,即始终使用相同的实例。我需要返回一个函数,这样每次使用它都会得到一个新实例。我的解决方案是有效的,我只是讨厌我必须完全重做语法,并且正在寻找更好的方法。
define(['plugins/http', 'durandal/app', 'knockout', 'lodash'], function (http, app, ko, _) {
    var ctor = function() {
        var displayName = 'Flickr',
        images = ko.observableArray([]),
        activate = function () {
            //the router's activator calls this function and waits for it to complete before proceeding
            if (images().length > 0) {
                return;
            }

            var that = this;
            return http.jsonp('http://api.flickr.com/services/feeds/photos_public.gne', { tags: 'mount ranier', tagmode: 'any', format: 'json' }, 'jsoncallback').then(function(response) {
                that.images(response.items);
            });
        },
        select = function(item) {
            //the app model allows easy display of modal dialogs by passing a view model
            //views are usually located by convention, but you an specify it as well with viewUrl
            item.viewUrl = 'views/detail';
            app.showDialog(item);
        },
        canDeactivate = function () {
            //the router's activator calls this function to see if it can leave the screen
            return app.showMessage('Are you sure you want to leave this page?', 'Navigate', ['Yes', 'No']);
        };

        _.extend(this, {
            displayName: displayName,
            images: images,
            activate: activate,
            select: select,
            canDeactivate: canDeactivate
        });
    };

    return ctor;
});