65.9K
CodeProject 正在变化。 阅读更多。
Home

JavaScript 命名空间

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.64/5 (15投票s)

2014 年 10 月 14 日

CPOL

4分钟阅读

viewsIcon

114503

JavaScript 命名空间

什么是命名空间

命名空间 是一组 标识符函数方法等的容器。 它为其内容提供了一定程度的组织,以便可以很好地区分和组织。

为什么需要命名空间

我们一定从任何语言中都了解了 命名空间。 它的作用是,它不允许我们污染我们的代码库,并通过对代码进行逻辑分组并避免意外和预期的冲突来使它更干净。

为了实现这一点,我们需要做的是在应用程序中创建一个命名空间并使用它。

在任何现代应用程序中,命名空间 是必须拥有的,因为最终我们需要第三方库和组件。

命名空间在 JavaScript 中的重要性

不幸的是,JavaScript 默认不提供命名空间。 因此,我们在 JavaScript 中创建的任何内容(函数方法对象变量)都是 全局 的,并且我们通过向其添加更多内容来继续污染该 全局命名空间

但好消息是我们可以 在 JavaScript 中创建命名空间,而且也很容易。
众所周知,在 JavaScript 中,一切都是一个对象,创建一个对象非常简单。 我们可以通过一些小的调整来轻松实现命名空间。

让我们看看 JavaScript 如何使所有东西都成为全局的

 //declare a function
function calculateTax(item) {
    return item.price * 1.40;
}
 
var product = function (cost) {

   this.cost = cost;
   this.getCost = function(){
      return this.cost;
   };
};
 
function doTaxCalculations() {

    var p = new product(100);
    alert(calculateTax(p.getCost()));
}

在上面的代码中,两个函数和类,这三个都位于全局空间中。
这是一个简单的代码库,但它包含 3 个全局项 (calculateTax, product, doTaxCalculations)。
如果我们使用第三方库并且它们也包含相同的名称,这三个将会给我们带来麻烦。
例如,如果它在其他库之前使用,它将被库覆盖,反之亦然。

JavaScript 命名空间示例

JavaScript 中,它只不过是一个 单一的全局对象,它将包含我们所有的 函数、方法、变量等。 这里 ‘MYAPPLICATION’ 作为 JavaScript 命名空间 并是唯一一个包含所有其他项目的 全局对象

var MYAPPLICATION = {
    calculateTax: function (item) {
        return item * 1.40;
    },
    product: function (cost) {
        this.cost = cost;
        this.getCost = function(){
                          return this.cost;
                       };
    },
    doTaxCalculations: function () {
        var p = new MYAPPLICATION.product(100);
        alert(this.calculateTax(p.getCost()));
    }
}

要访问任何 方法变量,您需要通过 MYAPPLICATION 获取它。

var newProduct = new MYAPPLICATION.product(200);
alert(p.getPrice());

不仅是像上面这样的单一命名空间,我们还可以创建 嵌套的 JavaScript 命名空间
让我们看一个嵌套 JavaScript 命名空间的示例。

嵌套 JavaScript 命名空间

它只不过是一个 命名空间 内部的 命名空间,它为 复杂的 JavaScript 应用程序 提供了更好的 模块化

var MYNESTEDAPPLICATION = {

    MODEL: {
        product: function (price) { 
			         this.price = price; 
			        this.getCost = function(){
			             return this.price;
			         };
			     }
    },
    LOGIC: {
        calculateTax: function (item) {
            return item * 1.40;
        },
        doCalculations: function () {
            var p = new MYNESTEDAPPLICATION.MODEL.product(100);
            alert(this.calculateTax(p.getCost()));
        }
    }
}

注意

Do your naming convention in such a manner that it will be self explanatory and 
not conflict other Library. May be I am not that good at those.

如果不存在则创建命名空间

像上面一样,我们使用一个单一的全局对象,但它可能与其他全局对象冲突。
为了避免这种情况,我们可以在创建它之前检查其是否存在,这是一个好习惯。

// not safe, if there's another object with this name we will overwrite it
var MYSAMPLEAPP = {};
 
// We need check before we create the namespace
if (typeof MYSAMPLEAPP === "undefined") {
    var MYSAMPLEAPP = {};
}
 
// shorter version
var MYSAMPLEAPP = MYSAMPLEAPP || {};

上面是创建命名空间最安全的方法,但我们可以做的是通过编写一个函数来使其更容易,该函数将创建我们的 命名空间

创建命名空间的函数

我们只需要使用一些参数调用一个简单的函数来创建我们的 命名空间。 然后,我们可以在该命名空间中定义所有函数和变量。

var MYNAMESPACE = MYNAMESPACE || {};
 
var newNamespace = MYNAMESPACE.createNameSpace("MYNAMESPACE.COUNTRY.STATES");
 
newNamespace.product = function(price) {
	this.price = price;
	this.getCost = function(){
	return this.price;
	}
};

MYNAMESPACE.createNameSpace = function (namespace) {
	
	//get the namespace string and split it
    var namespaceArr = namespace.split(".");
    var parent = MYNAMESPACE;
 
    // excluding the parent
    if (namespaceArr[0] === "MYNAMESPACE") {
        namespaceArr = namespaceArr.slice(1);
    }
 
    // loop through the array and create a nested namespace 
    for (var i = 0; i < namespaceArr.length; i++) {

        var partname = namespaceArr[i];

        // check if the current parent already has the namespace declared
        // if it isn't, then create it
        if (typeof parent[partname] === "undefined") {
            parent[partname] = {};
        }

        // get a reference to the deepest element in the hierarchy so far
        parent = parent[partname];
    }
    //  empty namespaces created and can be used.
    return parent;
};

基本上,createNameSpace 函数拆分 字符串 并从中创建一个嵌套命名空间。

MYNAMESPACE.createNameSpace("MYNAMESPACE.COUNTRY.STATES");

输出

var MYNAMESPACE = {
    COUNTRY: {
        STATES: {
        }
    }
}

命名空间别名

我们可以通过简单地将 命名空间 别名为一个局部变量来实现这一点

var state = MYNAMESPACE.COUNTRY.STATES;

使用 state 而不是整个命名空间来获取所有变量和函数。

注意

但是,上面关于 命名空间 的解决方案对于大多数情况来说是完全有效和有用的。
但可能存在某些情况,在这种情况下,这并不是最好的选择。
在这里,只有一个全局实例,但没有什么可以阻止我们直接访问内部变量。
不知何故,我们需要控制对 私有 变量的访问。 这可以通过 “使用模块创建模块化应用程序” 来实现,该模块将封装日期。

使用模块

MYAPP.MODEL.PRODUCTS.product = function(cost) {
    
    //cost is the private variable
    var cost = cost;   
    return {
        isTaxable: true,
        getCost: function(){                                               
            return cost;                                            
        }
    };
};

cost 可以被该函数访问,因为它属于 闭包,否则它不能被直接访问。
isTaxablegetCost公共 的。

有很多模式可以实现这一点。
例如,将所有内容设为私有,并公开我们需要公开的内容。

MYAPP.MODEL.PRODUCTS.product = function(cost){

  //everything  private
    var cost = cost;    
    var isTaxable = true;
    var getCost: function(){                                               
            return cost;                                            
        };
 	//expose what you need
    return {
        isTaxable: isTaxable,
        getCost: getCost
    };
};

尽管在上面编写的示例中可能存在一些安全问题,但我们可以使其越来越完美。
我们可以通过引用 命名空间 内的任何变量来阻止访问。 有很多我们可以遵循的模式来实现这一点。

结论

命名空间 的使用使 JavaScript 代码 模块化结构化,也易于阅读、理解和修改。 因此,在不污染全局命名空间的情况下,我们可以实现所有这些,无论如何我们都必须使用 全局命名空间,但我们并没有在那里搞砸。

希望这有帮助。 感谢您的阅读。

© . All rights reserved.