JavaScript命名空间模式实例详解


Posted in Javascript onJune 20, 2019

本文实例讲述了JavaScript命名空间模式。分享给大家供大家参考,具体如下:

前言

命名空间可以被认为是唯一标识符下代码的逻辑分组。为什么会出现命名空间这一概念呢?因为可用的单词数太少,并且不同的人写的程序不可能所有的变量都没有重名现象。在JavaScript中,命名空间可以帮助我们防止与全局命名空间下的其他对象或变量产生冲突。命名空间也有助于组织代码,有更强的可维护性和可读性。本文旨在探讨JavaScript里的几种常见命名空间模式,为我们提供一个思路。

JavaScript执行环境有很多独特之处,全局变量和函数的使用就是其中之一。JavaScript的执行环境由各种各样的全局变量构成,这些全局变量先于函数执行环境而创建。这些全局变量都挂载于“全局对象”下,在浏览器中,window对象就等同于全局对象。那么,在全局作用域中声明的任何变量和函数都是window对象的属性,当名称有冲突时,就会产生一些不可控的问题。全局变量会带来以下问题:

命名冲突

代码的脆弱性

难以测试

在编程开发中合理的使用命名空间,可以避免相同的变量或对象名称产生的冲突。而且,命名空间也有助于组织代码,有更强的可维护性和可读性。JavaScript中虽然没有提供原生的命名空间支持,但我们可以使用其他的方法(对象和闭包)实现类似的效果。下面就是一些常见的命名空间模式:

1.单一全局变量

JavaScript中一个流行的命名空间模式是选择一个全局变量作为主要的引用对象。因为每个可能的全局变量都成为唯一全局变量的属性,也就不用再创建多个全局变量,那么也就避免了和其他声明的冲突。

单一全局变量模式已经在不少的JavaScript类库中使用,如:

  • YUI定义了唯一的YUI全局对象
  • jQuery定义了和jQuery,和jQuery,由其他类库使用时使用jQuery
  • Dojo定义了一个Dojo全局变量
  • Closure类库定义了一个goog全局对象
  • Underscore类库定义了一个_ 全局对象

示例如下:

var myApplication = (function() {
  function() {
    // ***
  },
  return {
    // **
  }
})();

虽然单一全局变量模式适合某些情况,但其最大的挑战是确保单一全局变量在页面中是唯一使用的,不会发生命名冲突。

2.命名空间前缀

命名空间前缀模式其思路非常清晰,就是选择一个独特的命名空间,然后在其后面声明声明变量、方法和对象。示例如下:

var = myApplication_propertyA = {};
var = myApplication_propertyA = {};
function myApplication_myMethod() {
  // ***
}

从某种程度上来说,它确实减少了命名冲突的发生概率,但其并没有减少全局变量的数目。当应用程序规模扩大时,就会产生很多的全局变量。在全局命名空间内,这种模式对其他人都没有使用的这个前缀有很强的依赖,而且有些时候也不好判断是否有人已经使用某个特殊前缀,在使用这种模式时一定要特别注意。

3.对象字面量表示法

对象字面量模式可以认为是包含一组键值对的对象,每一对键和值由冒号分隔,键也可以是代码新的命名空间。示例如下:

var myApplication = {
  // 可以很容易的为对象字面量定义功能
  getInfo:function() {
    // ***
  },
  // 可以进一步支撑对象命名空间
  models:{},
  views:{
    pages:{}
  },
  collections:{}
};

与为对象添加属性一样,我们也可以直接将属性添加到命名空间。对象字面量方法不会污染全局命名空间,并在逻辑上协助组织代码和参数。并且,这种方式可读性和可维护性非常强,当然我们在使用时应当进行同名变量的存在性测试,以此来避免冲突。下面是一些常用的检测方法:

var myApplication = myApplication || {};
if(!myApplication) {
  myApplication = {};
}
window.myApplication || (window.myApplication || {});
// 针对jQuery
var myApplication = $.fn.myApplication = function() {};
var myApplication = myApplication === undefined ? {} :myApplication;

对象字面量为我们提供了优雅的键/值语法,我们可以非常便捷的组织代码,封装不同的逻辑或功能,而且可读性、可维护性、可扩展性极强。

4.嵌套命名空间

嵌套命名空间模式可以说是对象字面量模式的升级版,它也是一种有效的避免冲突模式,因为即使一个命名空间存在,它也不太可能拥有同样的嵌套子对象。示例如下:

var myApplication = myApplication || {};
// 定义嵌套子对象
myApplication.routers = myApplication.routers || {};
myApplication.routers.test = myApplication.routers.test || {};

当然,我们也可以选择声明新的嵌套命名空间或属性作为索引属性,如:

myApplication['routers'] = myApplication['routers'] || {};

使用嵌套命名空间模式,可以使代码易读且有组织性,而且相对安全,不易产生冲突。其弱点是,如果我们的命名空间嵌套过多,会增加浏览器的查询工作量,我们可以把要多次访问的子对象进行局部缓存,以此来减少查询时间。

5.立即调用的函数表达式

立即调用函数(IIFE)实际上就是匿名函数,被定义后立即被调用。在JavaScript中,由于变量和函数都是在这样一个只能在内部进行访问的上下文中被显式地定义,函数调用提供了一种实现私有变量和方法的便捷方式。IIFE是用于封装应用程序逻辑的常用方法,以保护它免受全局名称空间的影响,其在命名空间方面也可以发挥其特殊的作用。示例如下:

// 命名空间和undefined作为参数传递,确保:
// 1.命名空间可以在局部修改,不重写函数外部上下文
// 2.undefined 的参数值是确保undefined,避免ES5规范里定义的undefined
(function (namespace, undefined) {
// 私有属性
var foo = "foo";
  bar = "bar";
// 公有方法和属性
namespace.foobar = "foobar";
namespace.sayHello = function () {
  say("Hello World!");
};
// 私有方法
function say(str) {
  console.log("You said:" + str);
};
})(window.namespace = window.namespace || {});

可扩展性是任何可伸缩命名空间模式的关键,使用IIFE可以轻松实现这一目的,我们可以再次使用IIFE给命名空间添加更多的功能。

6.命名空间注入

命名空间注入是IIFE的另一个变体,从函数包装器内部为一个特定的命名空间“注入”方法和属性,使用this作为命名空间代理。这种模式的优点是可以将功能行为应用到多个对象或命名空间。示例如下:

var myApplication = myApplication || {};
myApplication.utils = {};
(function () {
  var value = 5;
  this.getValue = function () {
    return value;
  }
  // 定义新的子命名空间
  this.tools = {};
}).apply(myApplication.utils);
(function () {
  this.diagnose = function () {
    return "diagnose";
  }
}).apply(myApplication.utils.tools);
// 同样的方式在普通的IIFE上扩展功能,仅仅将上下文作为参数传递并修改,而不是仅仅使用this

还有一种使用API来实现上下文和参数自然分离的方法,该模式感觉更像是一个模块的创建者,但作为模块,它还提供了一个封装解决方案。示例如下:

var ns = ns || {},
  ns1 = ns1 || {};
// 模块、命名空间创建者
var creator = function (val) {
  var val = val || 0;
  this.next = function () {
    return val ++ ;
  };
  this.reset = function () {
    val = 0;
  }
}
creator.call(ns);
// ns.next, ns.reset 此时已经存在
creator.call(ns1, 5000);
// ns1包含相同的方法,但值被重写为5000了

命名空间注入是用于为多个模块或命名空间指定一个类似的功能基本集,但最好是在声明私有变量或者方法时再使用它,其他时候使用嵌套命名空间已经足以满足需要了。

7.自动嵌套的命名空间

嵌套命名空间模式可以为代码单元提供有组织的结构层级,但每次创建一个层级时,我们也得确保其有相应的父层级。当层级数量很大时,会给我们带来很大的麻烦,我们不能快速便捷的创建想创建的层级。那么如何解决这个问题呢?Stoyan Stefanov提出,创建一个方法,其接收字符串参数作为一个嵌套,解析它,并自动用所需的对象填充基本名称空间。下面是这种模式的一种实现:

function extend(ns, nsStr) {
  var parts = nsStr.split("."),
    parent = ns,
    pl;
  pl = parts.length;
  for (var i = 0; i < pl; i++) {
    // 属性如果不存在,则创建它
    if (typeof parent[parts[i]] === "undefined") {
      parent[prats[i]] = {};
    }
    parent = parent[parts[i]];
  }
  return parent;
}
// 用法
var myApplication = myApplication || {};
var mod = extend(myApplication, "module.module2");

以前我们必须为其命名空间将各种嵌套显式声明为对象,现在用上述更简洁、优雅的方式就实现了。

更多关于JavaScript相关内容可查看本站专题:《JavaScript常用函数技巧汇总》、《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》及《JavaScript数学运算用法总结》

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
JavaScript实现表格排序方法
Jun 14 Javascript
Query中click(),bind(),live(),delegate()的区别
Nov 19 Javascript
Javascript实现返回上一页面并刷新的小例子
Dec 11 Javascript
JavaScript返回当前会话cookie全部键值对照的方法
Apr 03 Javascript
Knockout自定义绑定创建方法
Dec 26 Javascript
JS仿hao123导航页面图片轮播效果
Sep 01 Javascript
老生常谈js数据类型
Aug 03 Javascript
JavaScript 中的 this 简单规则
Sep 19 Javascript
小程序日历控件使用方法详解
Dec 29 Javascript
vue-froala-wysiwyg 富文本编辑器功能
Sep 19 Javascript
js+canvas实现转盘效果(两个版本)
Sep 13 Javascript
ant design vue 表格table 默认勾选几项的操作
Oct 31 Javascript
npm的lock机制解析
Jun 20 #Javascript
express如何解决ajax跨域访问session失效问题详解
Jun 20 #Javascript
JS去除字符串最后的逗号实例分析【四种方法】
Jun 20 #Javascript
如何在微信小程序中实现Mixins方案
Jun 20 #Javascript
js JSON.stringify()基础详解
Jun 19 #Javascript
使用jquery-easyui的布局layout写后台管理页面的代码详解
Jun 19 #jQuery
Vue-Cli 3.0 中配置高德地图的两种方式
Jun 19 #Javascript
You might like
十大“创意”战术!
2020/03/04 星际争霸
php 404错误页面实现代码
2009/06/22 PHP
彻底搞懂PHP 变量结构体
2017/10/11 PHP
PHP的mysqli_ssl_set()函数讲解
2019/01/23 PHP
jQuery+PHP实现图片上传并提交功能
2020/07/27 PHP
JavaScript接口实现代码 (Interfaces In JavaScript)
2010/06/11 Javascript
jQuery产品间断向下滚动效果核心代码
2014/05/08 Javascript
javascript实现节点(div)名称编辑
2014/12/17 Javascript
JavaScript实现文字跟随鼠标特效
2015/08/06 Javascript
JSON 对象未定义错误的解决方法
2016/09/29 Javascript
使用原生的javascript来实现轮播图
2017/02/24 Javascript
Vue.js 单页面多路由区域操作的实例详解
2017/07/17 Javascript
JQuery用$.ajax或$.getJSON跨域获取JSON数据的实现代码
2017/09/23 jQuery
JSON字符串操作移除空串更改key/value的介绍
2019/01/05 Javascript
JavaScript碰撞检测原理及其实现代码
2020/03/12 Javascript
全面解析JavaScript Module模式
2020/07/24 Javascript
vue实现两个区域滚动条同步滚动
2020/12/13 Vue.js
Python学习笔记整理3之输入输出、python eval函数
2015/12/14 Python
Python常用的爬虫技巧总结
2016/03/28 Python
使用Python爬了4400条淘宝商品数据,竟发现了这些“潜规则”
2018/03/23 Python
python 重命名轴索引的方法
2018/11/10 Python
Python中的异常处理try/except/finally/raise用法分析
2019/02/28 Python
python处理“
2019/06/10 Python
flask应用部署到服务器的方法
2019/07/12 Python
使用Python画出小人发射爱心的代码
2019/11/23 Python
Python 实现向word(docx)中输出
2020/02/13 Python
利用Canvas模仿百度贴吧客户端loading小球的方法示例
2017/08/13 HTML / CSS
Html5中的桌面通知Notification的实现
2018/09/25 HTML / CSS
美国珠宝店:Helzberg Diamonds
2018/10/24 全球购物
应届生人事助理求职信
2013/11/09 职场文书
售后服务承诺书模板
2014/05/21 职场文书
对党的十八届四中全会的期盼
2014/10/17 职场文书
刑事辩护授权委托书范本
2014/10/17 职场文书
见义勇为事迹材料
2014/12/24 职场文书
秦兵马俑导游词
2015/02/02 职场文书
Three.js实现雪糕地球的使用示例详解
2022/07/07 Javascript