zoukankan      html  css  js  c++  java
  • JavaScript基础对象创建模式之命名空间(Namespace)模式(022)

    JavaScript中的创建对象的基本方法有字面声明(Object Literal)和构造函数两种,但JavaScript并没有特别的语法来表示如命名空间、模块、包、私有属性、静态属性等等面向对象程序设计中的概 念。为了让JavaScript实现面向对象程序中的高级语义,人们发明了命名空间模式、依赖声明模式,模块模式,以及沙盘模式。

    1. 命名空间模式
    命 名空间模式解决了JavaScript中的两个问题,一是全局变量污染的问题,二是可能的名字冲突问题。虽然JavaScript没有特别支持命名空间, 但命名空间模式在JavaScript中并不难实现。为了不过多使用全局变量,可以把程序中所有使用到的全局变量组织到一个(最好是一个程序只有一个)全 局的对象中去。接下来,要访问需要的变量,就可以通过这个对象来得到引用:
    // BEFORE: 5 globals
    // Warning: antipattern
    // constructors
    function Parent() {}
    function Child() {}
    // a variable
    var some_var = 1;
    // some objects
    var module1 = {};
    module1.data = {a: 1, b: 2};
    var module2 = {};
    
    上面的代码里有5个全局变量,有全局的对象,也有全局的简单类型的变量。下面建立一个全局对象,名字比如说叫MYAPP,然后把上面的5个全局变量都组织到MYAPP里:
    // AFTER: 1 global
    // global object
    var MYAPP = {};
    // constructors
    MYAPP.Parent = function () {};
    MYAPP.Child = function () {};
    // a variable
    MYAPP.some_var = 1;
    // an object container
    MYAPP.modules = {};
    // nested objects
    MYAPP.modules.module1 = {};
    MYAPP.modules.module1.data = {a: 1, b: 2};
    MYAPP.modules.module2 = {};
    
    这个全局对象的名字,可以选择使用程序的名字,也可以用域名,也可以用公司名。通常这个全局对象的名字是全大写的,以便看起来醒目些,但它并不是常量(常量通常也是全大写的)。
    这种模式可以很好的解决命名冲突的问题,因为不同程序或公司的代码里使用的变量,都被组织到不同的全局对象中,因此许多JavaScript的库都是用这种方式来组织API的。但这种模式也有些小问题:
    • 变量使用起来需要敲更多的字母,js文件也因此变得更大;
    • 只有一个全局变量使得所有的代码都可以使用它并修改它,这种修改可以即时生效;
    • 长的嵌套的名字使得变量的解析过程需要更长的时间。
    后面还将介绍的沙盘模式将应对这些问题。
    2. 通用的命名空间函数
    当程序变得越来越大之后,使用这个变量之前才在全局对象中声明它变得不再安全:一些属性和对象可能已经在全局对象中存在,重新声明它将把它原有的内容覆盖,因此我们在声明变量时就需要先做个简单的检查:
    // unsafe
    var MYAPP = {};
    // better
    if (typeof MYAPP === "undefined") {
        var MYAPP = {};
    }
    // or shorter
    var MYAPP = MYAPP || {};
    
    上面的检查是简单有效的,但十分繁琐: 在使用MYAPP.modules.module2这前,需要做3次检查。因此就需要有一个叫namespace()的函数,在每次使用声明一个模块或变量之前,做相应的检查:
    // using a namespace function
    MYAPP.namespace('MYAPP.modules.module2');
    // equivalent to:
    // var MYAPP = {
    //     modules: {
    //         module2: {}
    //     }
    // };
    
    下面就是一个通用的namespace()函数的实现:
    var MYAPP = MYAPP || {};
    MYAPP.namespace = function (ns_string) {
        var parts = ns_string.split('.'),
            parent = MYAPP,
            i;
        // strip redundant leading global
        if (parts[0] === "MYAPP") {
            parts = parts.slice(1);
        }
        for (i = 0; i < parts.length; i += 1) {
            // create a property if it doesn't exist
            if (typeof parent[parts[i]] === "undefined") {
                parent[parts[i]] = {};
            }
            parent = parent[parts[i]];
        }
        return parent;
    };
    
    有了上面的namespace()函数,我们就可以这样做了:
    // assign returned value to a local var
    var module2 = MYAPP.namespace('MYAPP.modules.module2');
    module2 === MYAPP.modules.module2; // true
    // skip initial `MYAPP`
    MYAPP.namespace('modules.module51');
    // long namespace
    MYAPP.namespace('once.upon.a.time.there.was.this.long.nested.property');
    
    这样我们就声明了一个很长的嵌套命名空间:
    JavaScript基础 022 - 对象创建模式之命名空间(Namespace)模式 - zihui.lin - Zihui的空间
     
  • 相关阅读:
    如何实现一个教师与学生教学辅助平台?
    面向过程(或者叫结构化)分析方法与面向对象分析方法到底区别在哪里?请根据自己的理解简明扼要的回答。
    2..移动APP开发使用什么样的原型设计工具比较合适?
    new delete和malloc free的区别
    char * 和char[]的区别以及怎样与string类型进行转换
    浅谈const的基本用法
    c++ map按key或value的值分别进行排序
    二叉树及先序,中序,后序遍历
    c++发展趋势
    markdown 的基本操作
  • 原文地址:https://www.cnblogs.com/Bryran/p/3976134.html
Copyright © 2011-2022 走看看