<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>把生成命名空间的方法绑定在jQuery上</title><script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script><script type="text/javascript">// 把生成命名空间的方法绑定在jQuery上  jQuery.namespace = function() {  var a=arguments, o=null, i, j, d;    for (i=0; i<a.length; i=i+1) {        d=a[i].split(".");        o=jQuery;        for (j=(d[0] == "jQuery") ? 1 : 0; j<d.length; j=j+1) {            o[d[j]]=o[d[j]] || {};            o=o[d[j]];        }    }    return o;};  // 定义命名空间  jQuery.namespace( 'jQuery.first.hello' );  jQuery.first.hello = function() {  alert( 'My first hello function' );  };  //调用
    jQuery.first.hello();  </script>
</head>
<body></body>
</html>

生成命名空间的方法绑定到jquery上

阿里员工写的开源数据库连接池的druid的源代码时,发现了其中在jquery的原代码中又定义了一个命名空间的函数:$.namespace(),其代码如下:

<script type="text/javascript" src="js/jquery-1.11.1.min.js"></script> <script type="text/javascript"> $.namespace("druid.index"); druid.index=function(){ var i,j; // 定义变量 return { login:function(){ //login 方法的实现 }, submit:function(){ // submit 方法的实现 } } } //使用命名空间的函数 druid.index.login(); druid.index.submit();

这样的话,就不会在全局变量区,引入很多的函数,将所有要使用的函数已经变量都放入了命名空间druid.index中,避免了不同js库中的函数名的冲突。

但是namespace函数的定义如何理解呢?

$.namespace = function() {  var a=arguments, o=null, i, j, d;  for (i=0; i<a.length; i=i+1) {  d=a[i].split(".");  o=window;  for (j=0; j<d.length; j=j+1) {  o[d[j]]=o[d[j]] || {};  o=o[d[j]];  }  }  return o;
};

思考了很久,思考的过程明白一个额外的知识点:window这个引用的是不可覆盖的。比如我们看下面的代码:

console.log(window);
window = {};
console.log(window);
window = null;
console.log(window);
window = undefined;
console.log(window);

打印的结果都是 window, 而不会是 null 或者 undefined。也就是说window这个名称,实质上是个引用或者说指针,他指向heap上的全局window对象,stack上的window引用指向heap上的全局window对象,这个指向关系是不可覆盖,不可修改的。上面我修改了stack上的window,视图让他指向Null对象,但是修改是无效的。

我们利用firebug来调试看看命名空间到底是如何实现的,我们一步一步的接近目标,先看如下代码:

(function(){  var o = window;console.log(o);    // 打印Window    o.druid={};console.log(o);    // 打印Windowconsole.log(o.druid);    // 打印 Object {}
})(); 

firebug中显示的对象为:

上面这个结果应该很好理解,因为 o指向了window,所以o.index = {}; 也就相当于 window.index = {}; 在window上定义了一个名叫index的对象。

下面我们在上面的代码上加码,在前进一步,接着看:

(function(){  var o = window;console.log(o);    // 打印Window    o.druid={};console.log(o);    // 打印Windowconsole.log(o.druid);    // 打印 Object {}
o = o.druid;console.log(o);    // 打印 Object {}console.log(window);    // 打印Windowconsole.log(o.druid);    // 打印  undefined
})();

对应firebug中对象和上一步一样,没有变化:

上面的代码中:o = o.druid; 之后,因为 o 是指向 window,为什么console.log(o);  打印 Object {};而 console.log(window); 打印输出Window呢?这里的原因是,没有理解引用的含义。o 和 window 都是stack上的一个变量,他们都指向heap上的全局window对象,我们修改 o 这个引用,让它指向另外的一个空对象,而这并不会同时修改stack上的window这个引用的指向。也就是就像两条绳子 a, b 都指向一条船,我让其中的一条绳子b指向第二条船,并不会影响绳子a还指向第一条船。

o = o.druid; 执行之后,o 不再执行window对象了,而是指向了window.druid对象,那么最后的console.log(o.druid);为什么打印输出 undefined 呢?很简单,因为 o 已经指向了 window.druid; 而window.druid是个空对象,其下并没有个druid的属性,所以自然就打印输出 undefined 了。

也就是说最后的console.log(o.druid); 就相当于 console.log(window.druid.druid);

好,理解了上面的代码,我们在加上一段代码:

(function(){  var o = window;console.log(o);    // 打印Window    o.druid={};console.log(o);    // 打印Windowconsole.log(o.druid);    // 打印 Object {}
o = o.druid;console.log(o);    // 打印 Object {}console.log(window);    // 打印Windowconsole.log(o.druid);    // 打印  undefined
o.index = {};console.log(o.index);    // 打印 Object {}o = o.index;console.log(o.index);    //  undefined
})(); 

对应的firebug中显示的对象为:

我们看到了已经形成了我们需要的命名空间:window.druid.index ,其实命名空间是使用对象链条来实现的。

因为 o = o.druid; 之后,o 已经指向了 window.druid ,那么 o.index = {}; 就相当于 window.druid.index = {};

而 后面的 o = o.index; 又将 o 对象变成了一个空对象,不再指向 window.druid,打印一个空对象的 index 属性自然就输出 undefined.

到这里已经就可以完全理解namespace函数的定义了。

其实核心知识点的有三条:

1)利用了 window 这个特殊引用的不可覆盖性,不可修改;

2)命名空间其实是对象链条来模拟的;

3)理解引用的含义:引用是个在stack上的变量,可以修改它指向不同的对象,要访问或者说修改他指向的对象,必须使用 “.” 点操作符,比如 o.index ={}; 而单纯的修改 o ,比如 o = {}; 并不会修改他指向的对象,因为 没有访问到他指向的对象,怎么能修改到他指向的对象呢?

转载于:https://www.cnblogs.com/hubing/p/4527721.html

深入剖析js命名空间函数namespace相关推荐

  1. c++ 命名空间 using namespace std 是什么意思?

    简要意思就是使用标准库,想知道更清楚的继续读下面的. using namespace std 是什么意思? using namespace std 意思: using 和namespace都是C++的 ...

  2. 命名空间函数用法及例子

    命名空间函数的实现示例,如果命名空间存在,便不会再重新创建它. var MYAPP=MYAPP || {};MYAPP.namespace = function(ns_string){var part ...

  3. js自定义函数及参数问题

    js自定义函数的过程中,往往我们希望指定一些参数的默认值 很容易的会写出如下的js 方法 function test(a,b,c=1,d='id'){ return 1; } 但是定义完之后,浏览器会 ...

  4. python命名空间和闭包_Python函数基础实例详解【函数嵌套,命名空间,函数对象,闭包函数等】...

    本文实例讲述了Python函数基础用法.分享给大家供大家参考,具体如下: 一.什么是命名关键字参数? 格式: 在*后面参数都是命名关键字参数. 特点: 1.约束函数的调用者必须按照Kye=value的 ...

  5. 【转】JS回调函数--简单易懂有实例

    JS回调函数--简单易懂有实例 初学js的时候,被回调函数搞得很晕,现在回过头来总结一下什么是回调函数. 我们先来看看回调的英文定义:A callback is a function that is ...

  6. url的三个js编码函数escape(),encodeURI(),encodeURIComponent()简介

    转载地址:http://www.haorooms.com/post/js_escape_encodeURIComponent 引子 浏览器URl地址,上网一定会用到,但是浏览器地址有中文或者浏览器ur ...

  7. url的三个js编码函数escape(),encodeURI(),encodeURIComponent()简介【转】

    引子 浏览器URl地址,上网一定会用到,但是浏览器地址有中文或者浏览器url参数操作的时候,经常会用到encodeURIComponent()和decodeURIComponent()以及encode ...

  8. prototype.js常用函数及其用法

    prototype.js常用函数: 函数名  解释  举例  Element.toggle  交替隐藏或显示  Element.toggle(''div1'',''div2'')  Element.h ...

  9. C++ Primer 5th笔记(chap 18 大型程序工具)内联命名空间 (inline namespace)

    1. inline必须出现在命名空间第一次出现的地方 inline namespace FifthEd {//... }//后续再打开命名空间的时候可以写inline也可以不写 namespace F ...

最新文章

  1. 机器学习入门:一文让你快速了解机器学习
  2. 一文讲清HBase的存储结构
  3. maven安装_如何从官网下载Maven与安装Maven
  4. Qt Creator列表和其他数据模型
  5. iOS 够逼格的注释总结
  6. 【报告分享】清华大学126页PPT:2020-2021年元宇宙发展研究报告.pdf(附下载链接)...
  7. pip install -q git+https://github.com/tensorflow/docs.git报错
  8. TOP to Down设计简单例子 Creo3.0
  9. 7-15 计算圆周率 (C语言)
  10. pytorch深度学习任务模板demo
  11. 计算机u盘装系统,教你u盘装系统教程
  12. 牛!发出中国第一封电子邮件,注册登记域名CN,中国互联网之父传奇
  13. C3H5 3d立体魔方效果
  14. 24位RGB颜色转换为16位RGB
  15. 哈尔滨工业大学计算机系统大作业2022春
  16. ubuntu安装nvidia显卡驱动黑屏nvidia-smi黑屏-显卡故障
  17. 单片机系统不稳定情况
  18. Lenovo T460 Fn功能键切换
  19. *7-2 CCF 2015-09-2 日期计算
  20. 延伸未来世界 看元宇宙风华

热门文章

  1. 【Linux】一步一步学Linux——groups命令(93)
  2. 进度条设置_朋友圈可以设置quot;仅一个月可见quot;了,什么时候出语音进度条呢?内附陈粒小姐姐的新歌哦~...
  3. 线程基本编程——线程函数大全
  4. div弹窗如何设置不超出页面_js实现弹窗功能(以支付方式为例)
  5. ansible(5)——使用通配符操作ansible命令
  6. adb启动失败 ADB server didn't ACK
  7. Linux多线程编程(一)---多线程基本编程
  8. muduo学习笔记 - 第五章 高效的多线程日志
  9. c语言指针输出两个数的最大值和最小值,并求和,有些不清楚这样写为什么不行。
  10. 文件的文本打开方式和二进制打开方式的区别