资讯专栏INFORMATION COLUMN

模块化你的JS代码

CntChen / 430人阅读

摘要:为什么要使用模块模式因为在全局作用域中声明的变量和函数都自动成为全局对象的属性,这经常会导致命名冲突,还会导致一些非常重要的可维护性难题,全局变量越多,引入错误的概率就越大所以我们应当尽可能少地使用全局变量,模块化的目的之一就是为了解决该问

为什么要使用模块模式?

因为在全局作用域中声明的变量和函数都自动成为全局对象Window的属性,这经常会导致命名冲突,还会导致一些非常重要的可维护性难题,全局变量越多,引入错误BUG的概率就越大!所以我们应当尽可能少地使用全局变量,模块化的目的之一就是为了解决该问题的!

零全局变量模式

该模式应用场景较少,通过一个IIFE(立即执行的匿名函数),将所有代码包装起来,这样一来所有的变量、函数都被隐藏在该函数内部,不会污染全局。

使用情景:

当该代码不会被其它代码所依赖时;

当不需要在运行时不断的扩展或修改该代码时;

当代码较短,且无需和其它代码产生交互时;

单全局变量模式 基本定义

单全局变量模式即只创建一个全局变量(或尽可能少地创建全局变量),且该全局变量的名称必须是独一无二的,不会和现在、将来的内置API产生冲突,将所有的功能代码都挂载到这个全局变量上。

它已经被广泛应用于各种流行的类库中,如:

YUI定义了唯一的YUI全局对象

JQuery定义了两个全局对象,$和JQuery

Dojo定义了一个dojo全局对象

Closure定义了一个goog全局对象

例子:

var Mymodule= {};

Mymodule.Book = function(){...};
Mymodule.Book.prototype.getName = function(){....};

Mymodule.Car = function(){...};
Mymodule.Car.prototype.getWheels = function(){....};
一个模块的定义

模块是一种通用的功能片段,它并没有创建新的全局变量或命名空间,相反,所有的代码都存放于一个单函数中,可以用一个名称来表示这个模块,同样这个模块可以依赖其他模块。

function CoolModule(){
        var something = "cool";
        var another = [1,2,3];
        function doSomething(){
            console.log( something);
        }
        function doAnother(){
            console.log(another.join("!"));
        }
        return {
            doSomething: doSomething,
            doAnother: doAnother
        };
}
var foo = CoolModule();
foo.doSomething(); //cool
foo.doAnother(); //1!2!3

这里的CoolModule 就是一个模块,不过它只是一个函数,这里调用CoolModule函数来创建一个模块的实例foo,此时就形成了闭包(因为CoolModule返回一个对象,其中的一个属性引用了内部函数),模块CoolModule返回的对象就是该模块的公共API(也可以直接返回一个内部函数)

所以,模块模式需要具备两个必要条件:

必须有外部的封闭函数,且该函数必须至少被调用一次(每次调用都会创建一个新的模块实例),如CoolModule

封闭函数必须至少有一个内部函数被返回,这样内部函数才能在私有作用域中形成闭包,并且可以访问或修改私有的状态

单例模块模式的实现:

var foo = ( function CoolModule(){
        ...//代码同上例
})();
foo.doSomething();
foo.doAnother();

还可以通过在模块内部保留对公共API对象的内部引用,这样就可以在内部对模块实例进行修改,包括添加、删除方法和属性

function CoolModule(){
    var something = "cool";
    var another = [1,2,3];
    function change() {
        pubicAPI.doSomething = doAnother;
    }
    function doSomething(){
        console.log( something);
    }
    function doAnother(){
        console.log(another.join("!"));
    }
    var pubicAPI = {
        change: change,
        doSomething: doSomething
    };
    return pubicAPI;
}
var foo = CoolModule();
foo.doSomething(); //cool
foo.change();
foo.doSomething(); //1!2!3
var foo1 = CoolModule();
foo1.doSomething(); //cool
现代的模块机制

命名空间是简单的通过在全局变量中添加属性来表示的功能性分组。
将不同功能按照命名空间进行分组,可以让你的单全局变量变得井然有序,同时可以让团队成员能够知晓新功能应该在哪个部分中定义,或者去哪个部分查找已有功能。
例如:定义一个全局变量Y,Y.DOM下的所有方法都是和操作DOM相关的,Y.Event下的所有方法都是和事件相关的。

常见的用法是为每一个多带带的JS文件创建一个新的全局变量来声明自己的命名空间;

每个文件都需要给一个命名空间挂载功能;这时就需要首先保证该命名空间是已经存在的,可以在单全局变量中定义一个方法来处理该任务:该方法在创建新的命名空间时不会对已有的命名空间造成破坏,使用命名空间时也不需要再去判断它是否存在。

var MyGolbal = {
    namespace: function (ns) {
        var parts = ns.split("."),
            obj = this,
            i, len = parts.length;
        for(i=0;i

大多数模块依赖加载器或管理器,本质上都是将这种模块定义封装进一个友好的API

var MyModules = (function Manager() {
    var modules = {};
    function define(name, deps, impl) {
        for(var i=0; i

以上代码的核心是modules[name] = impl.apply(impl,deps);,为了模块的定义引入了包装函数(可以传入任何依赖),并且将模块的API存储在一个根据名字来管理的模块列表modules对象中;
使用模块管理器MyModules来管理模块:

MyModules.define("bar",[],function () {
    function hello(who) {
        return "let me introduce: "+who;
    }
    return{
        hello: hello
    };
});
MyModules.define("foo",["bar"],function (bar) {
    var hungry = "hippo";
    function awesome() {
        console.log(bar.hello(hungry).toUpperCase());
    }
    return {
        awesome: awesome
    };
});
var foo = MyModules.get("foo");
foo.awesome();//LET ME INTRODUCE: HIPPO
异步模块定义(AMD):
define("my-books", ["dependency1","dependency2"], 
    function (dependency1, dependency2) {
        var Books = {};
        Books.author = {author: "Mr.zakas"};
        return Books; //返回公共接口API
    }
);

通过调用全局函数define(),并给它传入模块名字、依赖列表、一个工厂方法,依赖列表加载完成后执行这个工厂方法。AMD模块模式中,每一个依赖都会对应到独立的参数传入到工厂方法里,即每个被命名的依赖最后都会创建一个对象被传入到工厂方法内。模块可以是匿名的(即可以省略第一个参数),因为模块加载器可以根据JavaScript文件名来当做模块名字。
要使用AMD模块,需要通过使用与AMD模块兼容的模块加载器,如RequireJS、Dojo来加载AMD模块

requre(["my-books"] , function(books){
            books.author;
            ...
   }
)

以上所说的模块都是是基于函数的模块,它并不是一个能被稳定识别的模式(编译器无法识别),它们的API语义只是在运行时才会被考虑进来。因此可以在运行时修改一个模块的API

未来的模块机制

ES6为模块增加了一级语法支持,每个模块都可以导入其它模块或模块的特定API成员,同样也可以导出自己的API成员;ES6的模块没有‘行内’格式,必须被定义在独立的文件中(一个文件一个模块)
ES6的模块API更加稳定,由于编译器可以识别,在编译时就检查对导入的API成员的引用是否真实存在。若不存在,则编译器会在运行时就抛出‘早期’错误,而不会像往常一样在运行期采用动态的解决方案;

bar.js

function hello(who) {
    return "let me introduce: "+who;
}
export hello; //导出API: hello

foo.js

//导入bar模块的hello()
import hello from "bar";

var hungry = "hippo";
function awesome() {
    console.log(hello(hungry).toUpperCase());
}
export awesome;//导出API: awesome

baz.js

//完整导入foo和bar模块
module foo from "foo";
module bar from "bar";
foo.awesome();

import可以将一个模块中的一个或多个API导入到当前作用域中,并分别绑定在一个变量上;

module会将整个模块的API导入并绑定到一个变量上;

export会将当前模块的一个标识符(变量、函数)导出为公共API;

模块文件中的内容会被当做好像包含在作用域闭包中一样来处理,就和函数闭包模块一样;

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80552.html

相关文章

  • <<编写可维护的javascript>> 笔记6(避免使用全局变量)

    摘要:执行环境在很多方面都有其独特之处全局变量和函数便是其中之一事实上的初始执行环境是由多种多样的全局变量所定义的这写全局变量在脚本环境创建之初就已经存在了我们说这些都是挂载在全局对象上的全局对象是一个神秘的对象它表示了脚本最外层上下文在浏览器中 JavaScript执行环境在很多方面都有其独特之处. 全局变量和函数便是其中之一. 事实上, js的初始执行环境是由多种多样的全局变量所定义的,...

    MoAir 评论0 收藏0
  • rollup文档翻译 中文文档

    摘要:既可以通过一个配置文件使用命令行接口来调用,也可以他自己的使用。使用最简单的方法就是通过命令行接口。命令缩写会以监视模式运行。这时运行下将不会有错误抛出,包含导入的组件。 介绍 概览 rollup是一个js打包器,用来将很细碎的js编译打包成大的复杂的东西,像是一个库或者一个应用。其使用了ES6自带的新标准来格式化和打包js代码,而不是原先的Commonjs或者AMD这类解决方案。ES...

    enrecul101 评论0 收藏0
  • ES6 的模块系统

    摘要:的模块系统被设计成让你可以一次性引入多个变量。动态静态,或者说规矩和如何打破规矩作为一门动态编程语言,令人惊讶地拥有一个静态的模块系统。只要你的需求都是静态的话,这个模块系统还是很的。 此文为翻译,原文地址在这儿:https://hacks.mozilla.org/2015/08/es6-in-depth-modules/ ES6 是 ECMAScript 第 6 版本的简称,这是新一...

    MudOnTire 评论0 收藏0
  • [译]npm入门指南

    摘要:博客地址这篇文章是我在众成翻译翻译的一篇文章,一篇的入门指南,原文链接的出现使得用写服务端应用成为可能。你可以看到,这个过程也安装了其他的模块,它们都是的所依赖的模块。但是,得到的输出信息会很冗长,我们可以加上来精简一下输出。 github 博客地址: https://github.com/zengxiaota... 这篇文章是我在 众成翻译 翻译的一篇文章,一篇 npm 的入门指南,...

    mrcode 评论0 收藏0
  • webpak最全的简单入门

    摘要:了解什么是官方文档是这样介绍的点我了解官方文档简单的来说,可以看做是模块打包机它做的事情是,分析你的项目结构,找到模块以及其它的一些浏览器不能直接运行的拓展语言,等,并将其转换和打包为合适的格式供浏览器使用。 了解webpack 什么是webpack 官方文档是这样介绍的:点我了解官方文档 简单的来说,WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaSc...

    FreeZinG 评论0 收藏0

发表评论

0条评论

CntChen

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<