Js中的命名空间(namespace)

时间: 2018-12-01阅读: 944标签: js知识

全局变量应该由有系统范围相关性的对象们保留,并且它们的命名应该避免含糊并尽量减少命名冲突的风险。在实践中,这意味着你应该避免创建全局对象,除非它们是绝对必须的。 不过,恩,这些你早都知道了……

所以你对此是怎么做的?传统方法告诉我们,最好的消除全局策略是创建少数作为潜在模块和子系统的实际命名空间的全局对象。我将探索几种有关命名空间的方式,并以我基于 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(); //0myApp.next(); //1var 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 codevar protoQueryMooJo = function() {  
    //everything}//user codevar thirdParty = {};
protoQueryMooJo.apply(thirdParty);


其他的考虑

我希望避免命名空间嵌套。它们很难追踪(对人和电脑都是)并且它们会让你的代码因为一些乱七八糟的东西变得很多。如 Peter Michaux 指出的,深度嵌套的命名空间可能是那些视图重新创建他们熟悉和热爱的长包链的老派 Java 开发者的遗产。

通过 .js 文件来固定一个单独的命名空间也是可以的(虽然只能通过命名空间注入或者直接分配每一个变量),不过你应该对依赖谨慎些。此外将命名空间绑定到文件上可以帮助读者更轻易弄清整个代码

因为 JavaScript 并没有正式的命名空间结构,所以有很多自然形成的方法。这个调查只详细说明了其中的一部分,可能有更好的技术我没有发现。我很乐意知道它们。

译文:@雷森图喵喜客 
链接:http://chengkang.me/2016/06/21/Namespacing%20in%20JavaScript/



站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

2.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/1466

关闭

为什么javascript不起作用?

JavaScript是一种属于网络的脚本语言,已经被广泛用于Web应用开发,常用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果。通常JavaScript脚本是通过嵌入在HTML中来实现自身的功能的。

Js如何获取ul中li的个数?

javascript如何获取ul中li的个数?下面本篇文章就来给大家介绍一下使用javascript获取ul中li个数的方法,希望对大家有所帮助。

javascript的Object. hasOwnProperty方法

hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中(非继承属性)是否具有指定的属性,如果 object 具有带指定名称的属性,则 hasOwnProperty 方法返回 true,否则返回 false。

原生js实现数组随机排列(数组乱序)的方法.【快速洗牌算法】

在开发中遇到这样的问题,需要将一组已知数组的顺序打乱,按照以前和现在的做法,总结了以下方法。

js实现获取手机相册并上传

当初有很多人说使用form方法将文件封装来上传,可是因为要照顾到从相机中选择图片,所以一直没有去做。 后来看到了Uploader的方法来传文件,感觉自己找到了 。是使用plus.uploader来完成的

JS中的词法作用域(静态作用域)和动态作用域

首先说明一下,JavaScript没有用动态作用域概念,但 this 机制却和动态作用域类似!JavaScript是通过作用域链的方式进行变量查找的,而JS作用域链是词法作用域,也就做静态作用域!词法作用域:在函数声明(定义)时确定的

Js常用基础算法

冒泡排序;插入排序 过程就像你拿到一副扑克牌然后对它排序一样;快速排序;回文字符串;翻转字符串;字符串中出现最多次数的字符;数组去重;二分查找

avaScript与WebAssembly进行比较+在哪些情况下会优于JavaScript

这是专门探索JavaScript及其构建组件的系列,在识别和描述核心元素的过程中,我们还分享了构建SessionStack时使用的一些经验法则,这是一个轻量级但健壮且高性能的JavaScript应用程序,以帮助用户实时查看和重现其Web应用程序的缺陷。

归并排序JavaScript实现_关于归并排序思路和代码实现

归并排序:其基本思想是分治策略,先进行划分,然后再进行合并,步骤是: 1.我们以数组[1, 5, 6, 2, 4, 3]举例,归并排序的第一步,将数组一分为2;2.接着将分成的数组继续一分为2,直到长度为1,我们构成如下二叉树(成树 从上往下)

手写JavaScript中的bind方法

bind方法返回的是一个绑定this后的函数,并且该函数并没有执行,需要手动去调用。(从这一点看bind函数就是一个高阶函数,而且和call,apply方法有区别)。bind方法可以绑定this,传递参数。注意,这个参数可以分多次传递。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!