簡體   English   中英

如何封裝和創建可維護的JavaScript

[英]How to Encapsulate and Create Maintainable JavaScript

我遇到了一個有趣的挑戰,我有以下代碼:

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所有內容放入另一個模塊。 因此,無論您使用什么具體的模塊實現,它都不會弄亂。

好吧,我至少在可讀性方面采用的方法是將函數聲明從return塊中拉出:

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的地圖實現,一個簡單的Google搜索“ map polyfill ”使我想到了這一點,看起來很不錯: http : //eriwen.github.io/smap.js/

似乎有機會使用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);

讓我們考慮一下您的代碼中的以下摘錄,據我了解,問題所在:

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

    ...

據我所知,我認為沒有必要定義屬性attribAattribZ ,然后進行設置,然后再為它們定義setter函數。 您只需在需要的位置和時間返回或訪問screen.get('x')

但是,由於某些原因,如果絕對必要,那么以下由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);
    }
}

如果此策略不能解決問題,或者您認為我對問題的理解不正確,請嘗試使情況更清楚,使我們更接近目標。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM