Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/grails/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何封装和创建可维护的JavaScript_Javascript_Design Patterns - Fatal编程技术网

如何封装和创建可维护的JavaScript

如何封装和创建可维护的JavaScript,javascript,design-patterns,Javascript,Design Patterns,我遇到了一个有趣的挑战,我有以下代码: Sm.screenfragment(function (screen, viewModel) { //This can grow very quickly and turn into a mess var attribA = screen.get('title'), ... ... attribZ = screen.get('status'); var setAttribA =

我遇到了一个有趣的挑战,我有以下代码:

Sm.screenfragment(function (screen, viewModel) {
    //This can grow very quickly and turn into a mess
    var attribA = screen.get('title'),
        ... 
        ... 
        attribZ = screen.get('status');

    var setAttribA = function (container) {
        //Do Stuff
    };
    ...
    ...
    var setAttribZ = function(event, viewName) {
        //Do Stuff
    };

    //So this can grow hundreads of lines and get messy.
    return {
        model: {
            //Do Stuff
        },
        create: function () {
            //Do Stuff
        },
        prepare: function (callback, config) {
            //Do Stuff
        },
        enter: function () {
            //Do Stuff
        },
        exit: function (callback) {
            //Do Stuff
        }
    };
});
我尝试了一些想法,但它们只会弄乱语法:

我想添加一个新的util对象,我可以构造util对象,所以它只添加了一点结构,但没有更多

Sm.screenfragment(function (screen, viewModel) {
    //Still can grow into a mess
    var util = {
            attribA : screen.get('title'),
            attribB : screen.get('status'),
            setAttribA : function (container) {
            //Do Stuff
            },
            setAttribB : function(event, viewName) {
            //Do Stuff
            }   
    };

    return {
        model: {
            //Do Stuff
        },
        create: function () {
            //Do Stuff
            util.setAttribA...
        },
        prepare: function (callback, config) {
            //Do Stuff
        },
        enter: function () {
            //Do Stuff
        },
        exit: function (callback) {
            //Do Stuff
        }
    };
});

然后使用点符号来获得属性,但这并不会使混乱消失。我正在重新阅读模块模式的内容,看看我是否可以在这里应用一些东西,我有一些极端的情况,我可以在文件顶部有几十个属性和函数,它只是破坏了结构。如何以更模块化的方式安排代码?这样它就不会变得杂乱无章了。

你的问题不能那么容易回答,因为有些信息丢失了。哪些方法使用哪些属性?这是一个在分析问题时应该解决的问题(不是在设计中,也肯定不是在代码中)。那么,您的代码的哪一部分需要与哪一部分解耦呢

要从更一般的层面回答问题,请执行以下操作:

如果您在一个模块内部实现了高内聚,模块之间实现了低耦合,那么它被认为是良好的面向对象设计(OOD)。在您的例子中,这意味着:如果您的所有方法都引用了您的所有属性,那么将其保存在一个大文件中被认为是良好的OOD。但通常情况下,现实世界中的问题并不是以这种单一的方式联系在一起的


如果你想去耦合一些东西,有一种说法,你应该去耦合那些彼此不交互的部分。在您的情况下,您可以(可能)将有关
attribA
的所有内容放在一个模块中,将有关
attribB
的所有内容放在另一个模块中。因此,无论您使用的是哪种具体的模块实现,它都不会变得一团糟。

您的问题不能那么容易回答,因为缺少一些信息。哪些方法使用哪些属性?这是一个在分析问题时应该解决的问题(不是在设计中,也肯定不是在代码中)。那么,您的代码的哪一部分需要与哪一部分解耦呢

要从更一般的层面回答问题,请执行以下操作:

如果您在一个模块内部实现了高内聚,模块之间实现了低耦合,那么它被认为是良好的面向对象设计(OOD)。在您的例子中,这意味着:如果您的所有方法都引用了您的所有属性,那么将其保存在一个大文件中被认为是良好的OOD。但通常情况下,现实世界中的问题并不是以这种单一的方式联系在一起的


如果你想去耦合一些东西,有一种说法,你应该去耦合那些彼此不交互的部分。在您的情况下,您可以(可能)将有关
attribA
的所有内容放在一个模块中,将有关
attribB
的所有内容放在另一个模块中。因此,无论您使用的是什么具体的模块实现,它都不会变得混乱。

好吧,至少在可读性方面,我采取的方法是将函数声明从返回块中拉出:

Sm.screenfragment(function (screen, viewModel) {
    //Still can grow into a mess
    var util = {
            attribA : screen.get('title'),
            attribB : screen.get('status'),
            setAttribA : function (container) {
            //Do Stuff
            },
            setAttribB : function(event, viewName) {
            //Do Stuff
            }   
    };

    var create = function() {
        //Do Stuff
        util.setAttribA...
    };

    var prepare = function(callback, config) {
        //Do Stuff
    };

    var enter = function() {
        //Do Stuff
    };

    var exit = function(callback) {
        //Do Stuff
    };

    return {
        model: {
            //Do Stuff
        },
        create: create,
        prepare: prepare,
        enter: enter,
        exit: exit
    };
});

然后,如果这些函数中的代码是泛型/模块化的,则将该代码提取到实用程序文件中,并从那里调用它们。至少在可读性方面,我采取的方法是从返回块中提取函数声明:

Sm.screenfragment(function (screen, viewModel) {
    //Still can grow into a mess
    var util = {
            attribA : screen.get('title'),
            attribB : screen.get('status'),
            setAttribA : function (container) {
            //Do Stuff
            },
            setAttribB : function(event, viewName) {
            //Do Stuff
            }   
    };

    var create = function() {
        //Do Stuff
        util.setAttribA...
    };

    var prepare = function(callback, config) {
        //Do Stuff
    };

    var enter = function() {
        //Do Stuff
    };

    var exit = function(callback) {
        //Do Stuff
    };

    return {
        model: {
            //Do Stuff
        },
        create: create,
        prepare: prepare,
        enter: enter,
        exit: exit
    };
});

然后,如果这些函数中的代码是通用/模块化的,那么将这些代码提取到实用程序文件中,并从那里调用它们

我同意@Waog的观点,良好的OOD可能是解决问题的方法。考虑到您正在为其编写
setAttribA
函数的对象上可能有很多属性,为什么不使用映射稍微清理一下代码呢?JavaScript可能有几十种映射实现,一个简单的“map polyfill”谷歌搜索让我找到了这一种,它看起来很不错:

我同意@Waog的观点,良好的OOD可能是解决您问题的方法。考虑到您正在为其编写
setAttribA
函数的对象上可能有很多属性,为什么不使用映射稍微清理一下代码呢?JavaScript可能有几十种映射实现,一个简单的“map polyfill”谷歌搜索让我找到了这一种,它看起来很不错:

似乎有机会使用OO方法来封装类似的功能。每个类都可以存在于自己的文件中。。。这似乎很好:

// In file attrs.js
function ScreenAttrs(screen) {
    this.screen = screen;
    this.attribA = screen.get('title');
    // ...
    // ... could even categorize attributes into separate methods
    // this.initFooAttrs();
    // this.initBarAttrs();
};

// In file modifier.js
var attrs = new ScreenAttrs(screen);

function AttribModifier(attributes) {
    this.attrs = attributes;
};

AttribModifier.prototype.setAttribA = function() {
    // .. do stuff w/ this.attrs.attribA
};
// ... etc.

// in api.js
var modifer = new AttribModifier(attrs);

function ScreenAPIImpl (modifier) {
    this.modifier = modifier;
};

ScreenAPIImpl.proxy = function(context, method) {
    return function() {
        return method.apply( context, args.concat( slice.call( arguments ) ) );
    };
};

ScreenAPIImpl.prototype.model = function (foo) {
    // operation with this.modifier.setAttribA
    // operation with this.modifier.attrs.attribA
};

ScreenAPIImpl.prototype.fetchAPI = function (screen, viewModel) {
    return {
        // Bind context of method to this object instance
        model: this.proxy(this, this.model),
        // ...
    };
};

// .. etc

var api = new ScreenAPIImpl(modifier);

Sm.screenfragment(api.fetchAPI(screen, viewModel));
这也打开了创建帮助器生成器类的大门,该类构造所有内容并返回最终API对象:

var api = CreateAPI(screen);

似乎有机会使用面向对象的方法来封装类似的功能。每个类都可以存在于自己的文件中。。。这似乎很好:

// In file attrs.js
function ScreenAttrs(screen) {
    this.screen = screen;
    this.attribA = screen.get('title');
    // ...
    // ... could even categorize attributes into separate methods
    // this.initFooAttrs();
    // this.initBarAttrs();
};

// In file modifier.js
var attrs = new ScreenAttrs(screen);

function AttribModifier(attributes) {
    this.attrs = attributes;
};

AttribModifier.prototype.setAttribA = function() {
    // .. do stuff w/ this.attrs.attribA
};
// ... etc.

// in api.js
var modifer = new AttribModifier(attrs);

function ScreenAPIImpl (modifier) {
    this.modifier = modifier;
};

ScreenAPIImpl.proxy = function(context, method) {
    return function() {
        return method.apply( context, args.concat( slice.call( arguments ) ) );
    };
};

ScreenAPIImpl.prototype.model = function (foo) {
    // operation with this.modifier.setAttribA
    // operation with this.modifier.attrs.attribA
};

ScreenAPIImpl.prototype.fetchAPI = function (screen, viewModel) {
    return {
        // Bind context of method to this object instance
        model: this.proxy(this, this.model),
        // ...
    };
};

// .. etc

var api = new ScreenAPIImpl(modifier);

Sm.screenfragment(api.fetchAPI(screen, viewModel));
这也打开了创建帮助器生成器类的大门,该类构造所有内容并返回最终API对象:

var api = CreateAPI(screen);

让我们考虑下面的代码摘录,我理解的问题在于:

Sm.screenfragment(function (screen, viewModel) {
    //This can grow very quickly and turn into a mess
    var attribA = screen.get('title'),
    ... 
    ... 
    attribZ = screen.get('status');

    var setAttribA = function (container) {
        //Do Stuff
    };
    ...
    ...
    var setAttribZ = function(event, viewName) {
        //Do Stuff
    };

    ...
就我所知,在我看来,没有必要定义属性
attribA
直到
attribZ
,然后设置它们,然后再次为它们定义setter函数。您只需返回或访问
screen.get('x')
where和when需要它

但如果出于某些原因,这是绝对必要的,那么jQuery推广的以下策略就足够了:

attributeX = function(x, container){
    // if x and container are undefined, then we can assume API caller intends to
    // read value of property 'x' otherwise, caller intends to write to the property.
    if(container){
        // don't forget to do stuff before setting!
        container.setProp(x); // you get the idea
    } else {
        // well we must have a 'container' to set a prop,
        // if we don't then caller must want to read.
        return screen.get(x);
    }
}

如果这个策略不能缓解这个问题,或者如果你认为我没有正确地理解问题,那么请尝试使情况更清楚,使我们更接近目标。

让我们考虑下面的代码摘录,我理解的问题在于:

Sm.screenfragment(function (screen, viewModel) {
    //This can grow very quickly and turn into a mess
    var attribA = screen.get('title'),
    ... 
    ... 
    attribZ = screen.get('status');

    var setAttribA = function (container) {
        //Do Stuff
    };
    ...
    ...
    var setAttribZ = function(event, viewName) {
        //Do Stuff
    };

    ...
就我所知,在我看来,没有必要定义属性
attribA
直到
attribZ
,然后设置它们,然后再次为它们定义setter函数。您只需返回或访问
screen.get('x')
where和when需要它

但是如果绝对必要的话