【译】JavaScript 中的定名空间

原文链接: Namespacing in JavaScript
译文原链: 【译】JavaScript 中的定名空间

全局变量应当由有体系局限相关性的对象们保存,而且它们的定名应当防止暧昧并只管削减定名争执的风险。在实践中,这意味着你应当防止建立全局对象,除非它们是相对必需的。

不过,恩,这些你早都晓得了……

所以你对此是怎样做的?传统要领通知我们,最好的消弭全局战略是建立少数作为潜伏模块和子体系的现实定名空间的全局对象。我将探究几种有关定名空间的体式格局,并以我基于 James Edwards 近来的一篇文章获得的一个文雅、平安和天真的解决方案完毕。

静态定名空间

我用静态定名空间作为那些定名空间标签现实上硬编码的解决方案的涵盖性术语。是的,你能够将一个定名空间从新分派给另一个,不过新的定名空间将会援用和旧的那一个一样的对象。

1.经由过程直接分派

最基本的要领。如许异常冗杂,而且假如你还想重定名这些定名空间,你就有得活儿干了。不过它是平安和清晰邃晓的。

var myApp = {}
myApp.id = 0;
myApp.next = function() {
    return myApp.id++;  
}
myApp.reset = function() {
    myApp.id = 0;   
}
window.console && console.log(
    myApp.next(),
    myApp.next(),
    myApp.reset(),
    myApp.next()
); //0, 1, undefined, 0 

你也能够经由过程运用this援用兄弟属性来使未来的保护更轻松一些,不过这有一点冒险由于没有什么能阻挠你的那些定名空间里的要领被从新分派。

var myApp = {}
myApp.id = 0;
myApp.next = function() {
    return this.id++;   
}
myApp.reset = function() {
    this.id = 0;    
}
myApp.next(); //0
myApp.next(); //1
var getNextId = myApp.next;
getNextId(); //NaN whoops!

2.运用对象字面量

如今我们只须要援用定名空间名一次,因而以后转变名字更简朴了一些(假定你还没重复援用这个定名空间)。仍有一个风险是this的值能够会抛出一个『欣喜』 – 不过假定在一个对象字面构造里定义的对象不会被从新分派相对平安一点。

var myApp = {
    id: 0,
    next: function() {
        return this.id++;   
    },
    reset: function() {
        this.id = 0;    
    }
}
window.console && console.log(
    myApp.next(),
    myApp.next(),
    myApp.reset(),
    myApp.next()
) //0, 1, undefined, 0

3.模块形式

我发明本身近来用模块形式更多。逻辑被一个要领包装从全局域断绝开了(通常是自挪用的),它返回一个代表这个模块公然接口的对象。经由过程马上挪用这个要领并分派效果给一个定名空间变量,我们就锁住了这个定名变量中模块的 API。另外,任何没有包含在返回值中的变量将永久坚持私有,只对援用他们的公然要领可见。

var myApp = (function() {
    var id= 0;
    return {
        next: function() {
            return id++;    
        },
        reset: function() {
            id = 0;     
        }
    };  
})();   
window.console && console.log(
    myApp.next(),
    myApp.next(),
    myApp.reset(),
    myApp.next()
) //0, 1, undefined, 0  

如上对象字面量例子,定名空间名字能够随意马虎替换,不过另有分外上风:对象字面量是四班的 – 它满是关于属性分派,没有支撑逻辑的空间。另外,一切属性必需被初始化,而且属性值没法随意马虎跨对象援用(因而,比方,内部闭包就不能够运用了)。模块形式没有任何上述束缚,而且给我们分外的隐私福利。

动态定名空间

我们也能够将这一节称为定名空间注入。定名空间由一个直接援用要领包装内部的代办代表 – 这意味着我们不再须要打包分派给定名空间的返回值。这让定名空间定义变得更天真而且让具有多个存在于自力定名空间中(或许以至在全局高低文中)的模块的自力实例。动态定名空间支撑模块形式的悉数特征并附加直观和可读性强的上风。

4.供应定名空间参数

在这里我们只是将定名空间作为参数传给自挪用要领。变量id是私有的,由于他并没有被分派给context

var myApp = {};
(function(context) { 
    var id = 0;
    context.next = function() {
        return id++;    
    };
    context.reset = function() {
        id = 0;     
    }
})(myApp);  
window.console && console.log(
    myApp.next(),
    myApp.next(),
    myApp.reset(),
    myApp.next()
) //0, 1, undefined, 0  

我们以至能够把context设置给全局对象(经由过程一个字的转变!)。这是库主们的庞大财产 – 他们能够将他们的特征包装在一个自挪用函数中,然后让用户来决议它们是否是全局的(John Resig 在他写 JQuery 时就是一个这个理论的初期采纳者)。

var myApp = {};
(function(context) { 
    var id = 0;
    context.next = function() {
        return id++;    
    };
    context.reset = function() {
        id = 0;     
    }
})(this);   
window.console && console.log(
    next(),
    next(),
    reset(),
    next()
) //0, 1, undefined, 0  

5.用this作为定名空间代办

James Edwads 近来宣布的一篇文章激起了我的兴致。《My Favorite JavaScript Design Patter》 明显被许多评论者误解了,他们以为他能够也是借助于模块形式。这篇文章宣扬了多种手艺(能够致使了读者的疑惑),但是在它的中心部份是一点我已修正并呈现为一个定名空间东西的很天赋的东西。

这个形式的美就在于它仅仅是根据这个言语被设想的体式格局运用 – 不多不少、不投契也不取巧。另外由于定名空间是经由过程this关键字(它在给定的实行高低文中是稳定的)注入的,它不能够被不测修正。

var myApp = {};
(function() {
    var id = 0;
 
    this.next = function() {
        return id++;    
    };
 
    this.reset = function() {
        id = 0;     
    }
}).apply(myApp);    
 
window.console && console.log(
    myApp.next(),
    myApp.next(),
    myApp.reset(),
    myApp.next()
); //0, 1, undefined, 0

更棒的是,apply(以及call) API 供应了与高低文和参数天然的断绝 – 因而给模块建立者通报附加参数异常清洁。下面的例子表清楚明了这一点,而且展现了如何自力于多个定名空间来运转模块。

var subsys1 = {}, subsys2 = {};
var nextIdMod = function(startId) {
    var id = startId || 0;
    this.next = function() {
        return id++;    
    };
    this.reset = function() {
        id = 0;     
    }
};
nextIdMod.call(subsys1);    
nextIdMod.call(subsys2,1000);   
window.console && console.log(
    subsys1.next(),
    subsys1.next(),
    subsys2.next(),
    subsys1.reset(),
    subsys2.next(),
    subsys1.next()
) //0, 1, 1000, undefined, 1001, 0

固然假如我们假如我们须要一个全局 id 生成器,异常简朴……

nextIdMod();    
window.console && console.log(
    next(),
    next(),
    reset(),
    next()
) //0, 1, undefined, 0

这个我们作为例子运用的 id 生成器东西并没有表现出这个形式的悉数潜力。经由过程包裹一全部库和运用this关键字作为定名空间的替身,我们使得用户在任何他们挑选的高低文中运转这个库很轻松(包含全局高低文)。

//library code
var protoQueryMooJo = function() {  
    //everything
}
//user code
var thirdParty = {};
protoQueryMooJo.apply(thirdParty);

其他的斟酌

我愿望防止定名空间嵌套。它们很难追踪(对人和电脑都是)而且它们会让你的代码由于一些杂乱无章的东西变得许多。如 Peter Michaux 指出的,深度嵌套的定名空间多是那些视图从新建立他们熟习和酷爱的长包链的老派 Java 开发者的遗产。

经由过程 .js 文件来牢固一个零丁的定名空间也是能够的(虽然只能经由过程定名空间注入或许直接分派每个变量),不过你应当对依靠郑重些。另外将定名空间绑定到文件上能够协助读者更随意马虎弄清全部代码。

由于 JavaScript 并没有正式的定名空间构造,所以有许多天然构成的要领。这个观察只细致说清楚明了个中的一部份,能够有更好的手艺我没有发明。我很愿意晓得它们。

更多文章

James Edwards: My Favorite JavaScript Design Pattern
Peter Michaux: JavaScript Namespacing

    原文作者:CHENGKANG
    原文地址: https://segmentfault.com/a/1190000005770218
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞