zoukankan      html  css  js  c++  java
  • 浅谈JavaScript 命名空间

    Javascript只有函数作用域,什么块儿啊、神马文件啊统统都认为是一个命名空间的,有时候因为一些重名问题导致的错误让人莫名其妙,难以调试解决。

    在JavaScript中全局变量经常会引起命名冲突,甚至有时侯重写变量也不是按照你想像中的顺序来的,可以看看下面的例子:

    var sayHello = function() {
      return 'Hello var';
    };
    
    function sayHello(name) {
      return 'Hello function';
    };
    
    sayHello();

    最终结果为

    > "Hello var"

    再来几个例子

            <input type="button" value="test" onclick="alert();"/>
            
            <script type="text/javascript">
                function alert(){
                    //.......
                    
                    test2();
                    //.......
                }
                
                function test2(){
                    alert('test2')
                }

    在个例子在不同的浏览器下有不同表现,IE会报Stack over flow, Firefox会死掉。。。反正都会报错,很简单的错误,代码中自定义了一个alert函数,在alert函数中调用了test2函数,test2函数中意图调用window的alert方法,这样循环调用了,也许看了你会说这么明显的错误谁会犯,但是如果自定义的方法叫close(这个经常会出现吧),然后内部调用了一个外部文件的函数,该函数调用了window的close方法,这样错误是不是隐蔽了很多呢。

    简单的命名空间

    由于JavaScript没有文件作用域,不同的函数分散在不同的文件中,甚至由不同的人编写,重名的概率大大增加。是不是足够小心就可以了呢?也不尽然,还有些意外情况,比如经常会用到继承,于是写了一个没出现过的函数名extend,不料在EcmaScript5中加入了extend函数,命名空间的必要性就体现出来了。

    JavaScript有函数的作用域,可以利用这点把自定义的函数写到一个函数体内,这样函数内的变量、对象、函数就像在一个命名空间内一样和外部隔离。

    复制代码
    <input type="button" value="test" onclick="(new namespace()).alert();"/>
            
            <script type="text/javascript">
                function namespace(){
                    this.alert=function(){
                        console.log('test');
                    }
                }
            </script>
    复制代码

    这样自定义的alert方法就不会和window的alert冲突了。

    简单进化

    这样可以是可以,但也有问题,最大的问题在于调用方式复杂而丑陋!每次调用的时候都要实例化对象,然后调用其方法,简单修改代码让其实现自动实例化。

    复制代码
    <input type="button" value="test" onclick="NS.alert();"/>
            
            <script type="text/javascript">
                (function namespace(){
                    this.alert=function(){
                        console.log('test');
                    }
                    
                    window.NS=this;
                })();
            </script>
    复制代码

    要看明白上面代码首先要了解一下“立即执行函数”(江湖人是这么称呼的)的技巧结构类似这样

    (function xxx(){
    
           //function body 
    
     })();

    这样写xxx函数就可以在定义完后自动执行,看起来神奇,其实上面写法可以拆成这样

    复制代码
    function xxx(){
    
           //function body 
    
     }
    
    xxx();
    复制代码

    就是定义一个函数,然后使用括号语法调用,而函数定义外面的一层括号只起到将函数声明转为函数定义表达式,因为只有表达式才可以使用括号调用。看明白这些妖蛾子之后上面代码就简单了,在自定义namespace函数最后把this赋值为window的NS属性,在调用的时候直接使用NS.xx就可以了。看起来好了很多。

    美化一下

    上面的写法看起来不错了,但是函数名namespace貌似是多余的了,可以美化一下

    复制代码
    (function (){
                    this.alert=function(){
                        console.log('test');
                    }
                    
                    window.NS=this;
                })();
    复制代码

    变成了一个立即执行的匿名函数,美化了一些,不过看起来还是怪怪的,对呀,明明是实例化的function,为什么方法定义不写到prototype中呢,匿名函数怎么写prototype。。。,还得动动脑筋

    复制代码
    (function(){
                    var _NS=function(){
                    
                    }
                    _NS.prototype.alert=function(){
                        console.log('test');
                    }
                    window.NS=new _NS();
                })();
    复制代码

    写几个有用的函数

    querySelector和querySelectorAll是W3C提供的新的查询接口,但是名字好长,自己写个简单的,innerHTML属性也常用到,写个简单版仿jQuery的html方法

    复制代码
    (function () {
                var _NS = function () {
                  
                }
             
                _NS.prototype.select = function (selector,context) {
                    var context = context || document;
                    return context.querySelectorAll(selector);
                }
    
                _NS.prototype.isArrayLike=function(obj){
                    if(obj instanceof Array){
                        return true;
                    }
    
                    var length=obj.length;
                    if ( obj.nodeType === 1 && length ) {
                        return true;
                    }
                    return false;
                }
    
                _NS.prototype.html = function (obj,value) {
                    var isArray=this.isArrayLike(obj), i=0;
    
                    if (typeof value == 'string') {
                        if (!isArray) {
                            obj.innerHTML = value;
                        } else {
                            var length = obj.length;
                            while (i < length) {
                                obj[i].innerHTML = value;
                                i += 1;
                            }
                        }
                    } else {
                        if (!isArray) {
                            return obj.innerHTML;
                        } else {
                            return obj[0].innerHTML;
                        }
                    }
                }
    
                window.NS = new _NS();
            })();
    复制代码

    这样一个带有命名空间的简单JavaScript库就写成了,不用担心命名冲突了,但是用起来很不方便啊,做前端的同学都用过jQuery,人家用起来那叫一个简单,jQuery是怎么做的?

    .

  • 相关阅读:
    SQL 去重 DISTINCT 语法
    urllib2 urllib urllib3的区别联系
    urllib库中常见的类和方法
    python模块之json pickle
    python os模块
    python的常见内置模块之-----time
    列表,队列,栈,链表的内存模型
    open函数
    session和cookie
    随笔小skill
  • 原文地址:https://www.cnblogs.com/fightjianxian/p/12397688.html
Copyright © 2011-2022 走看看