zoukankan      html  css  js  c++  java
  • JS模块化编程(三)

    AMD&CMD

    • 对象字面量

    对象字面量表示,其实就是用一对大括号括起来的键值对,也就是JavaScript 声明对象的方式

    var myObject = {
    variableKey : variableValue,
    functionKey : function() {
    ...
    }

    比较一下下面代码声明方式,使用对象字面量表示,可以减少全局变量的污染,

    一般来说,强烈建议在任何时候都不要使用下面的声明方式

    var variableName = ...;

    function f1(){
    ...
    }
    function f2(){
    ...
    }

    • 立即执行函数(IIFE Immediately-Invoked Function Expressions)

    立即执行函数是现在非常流行的写法,大部分JS 库都使用了这种技巧,主要是防止全局变量的污染。

    当我们在声明类似于

    var name1 = function (){ … } 这样的函数时,

    在后面加一对括号(),就可以让它立即执行,但是如果是

    function name1() { … }

    这样的函数,则会有问题:

    function f1(){
    alert("ok");
    }();//Unexpected token(意外的标记),因为后面的()会被解析为分组操作符

    解决上面的问题,只需要加上括号将function 代码全部括住即可,下面就是立即执行函数的声明方式:
    (function () { /* code */ } ());
    (function () { /* code */ })();

    上面两种方式都是可以的,主要看个人习惯。立即执行函数可以不对外暴露私有变量,比如:

    var myObject = {
          name : "my name",
          f1: function(){
          return this.name;
         }
    };
    myObject.name; //变量暴露在外
    myObject.f1(); //my name

    //对比下面立即执行函数隐藏私有变量

    var myObject = (function(){
               var name = "my name";
               return {
                            f1: function(){
                                      return name;
                              }
                         }
    })();

    myObject.name; //未定义
    myObject.f1(); //my name

    • 导入全局变量

    把全局变量作为参数传递给一个立即执行函数,这样就完成了全局变量的导入,

    立即执行函数中可以使用此全局变量的方法,并可以修改(简化)全局变量的名称

    var myobj= (function ( jq) {

                                             function f1(){
                                                                 jq(".class").html("test");
                                             }
                                            return{
                                                       f1: f1
                                            };
    })( jQuery );
    myobj.f1();

    • 模块导出

    当然,有导入也可以有导出,有时我们不仅要导入全局变量,也要把模块导出到全局空间
    供其他模块使用。通过在立即执行函数中返回一个Object,就可以实现模块导出功能:

    var myobj = (function () {

                            var obj = {},

                            attr1 = "属性1,私有";

                            function f1() { // ... }

                            obj.attr2 = "属性2,公共";

                            obj.f2 = f1;

                            return obj;

    })();

    • 扩展模块

    在开发中,我们经常会对一些模块进行扩展,扩展当然可以直接修改模块的源代码,

    但是这不是一个好的方法,比如我们要给 myModule 模块增加几个方法,

    通过前面的“立即执行函数”、“导入全局变量”、“模块导出”的知识,

    我们可以推导出下面的扩展方式:

    var myobj = (function ( obj ) {
    obj.fx = function () {
    //...
    };
    return obj;
    })( myobj);

    问题来了:上面的代码可以很好地对 myobj 进行扩展,不过前提是 myobj 必须
    已经定义,如果扩展的 fx方法和 myobj本身没有任何的依赖,那么要求
    myobj必须已经定义就毫无必要了,怎么解决这个问题呢,非常简单,只需要或一个
    空对象:

    //松散扩展
    var myobj = (function ( obj ) {
                 obj.xxMethod = function () {    //...
                };
        return my;
    })( myobj || {} );

    上述代码还存在一个问题,那就是如果a.js 中声明了 var myobj= …,b.js 中也声明
    了 var myobj= …,这样在引入a.js 和b.js 时,后者会将前者覆盖,这并不是我们期
    望的,所以对上述代码,可以再加改进:

    (function ( obj ) {
    obj.fx= function () {
    ...
    }
    })( window.myobj= window.myobj|| {} );

     

    • 再说AMD

    是“Asynchronous Module Definition”的缩写,意思就是“异步模块定义”。从名称上就
    可以看出,它是通过异步方式加载模块的,模块的加载不影响后续语句的执行,所有依赖
    加载中的模块的语句,都会放在一个回调函数中,等到该模块加载完成后,这个回调函数
    才运行。
    AMD 规范的API 非常简单:

    define(id?, dependencies?, factory);

    规范定义了一个define 函数,它用来定义一个模块。它包含三个参数,前两个参数都是可选的。
    第一个参数 id:是一个string 字符串,它表示模块的标识(也就是模块的路径,通过id 才能知道从什么位置去加载依赖的模块)
    第二个参数 dependencies:是一个数组,成员是依赖模块的id
    第三个参数 factory:是一个回调函数,在依赖的模块加载成功后,会执行这个回调
    函数,它的参数是所有依赖模块的引用,如果回调函数有返回值,会导出出来
    一个完整的模块定义包含模块名称,模块的依赖和回调函数,比如下面的代码:

    define("addlib", ["math"], function (math) {
    return {
    addTen : function (x) {
    return math.add(x, 10);
    }
    };
    });

    如果这个模块并没有依赖,那么默认的依赖是["require", "exports", "module"],这时模块可
    以改写为:

    define("adder", function (require, exports) {
    exports.addTen = function (x) {
    return x + 10;
    };
    });

    如果省略第一个参数,则会定义一个匿名模块,见代码:

    define(["math"], function (math) {
    return {
    addTen : function (x) {
    return math.add(x, 10);
    }
    };
    });

    在实际中,使用的更多的是匿名模块定义方式,因为这样更加的灵活,模块的标识和它的
    源代码不再相关,开发人员可以把这个模块放在任意的位置而不需要修改代码。一般只有
    在要使用工具打包模块到一个文件中时,才会声明第一个参数,所以应该尽量避免给模块
    命名。

     

    在写模块的时候,也有可能没有依赖或者稍后才需要加载依赖,也就是说我们可以省略第
    一个和第二个参数,下面代码展示了这种用法,这也是CommonJS 的写法,算是一种兼
    容:

    define(function (require, exports, module) {
    ……
    var a = require('a'),
    b = require('b');
    exports.action = function () {
    ……
    };
    });

    注意上述回调函数里的require 的使用将被自动进行动态加载。

  • 相关阅读:
    JavaScript-循环
    JavaScript-条件判断
    JavaScript-对象
    Vue快速入门
    Typora中的MarkDown语法
    (已解决)ERROR: In file './docker-compose.yml', service 'networks' must be a mapping not an array
    mac常用快捷键
    Python数据分析
    Python列表和元组
    Selenium工具爬取商品
  • 原文地址:https://www.cnblogs.com/jeffry/p/5335982.html
Copyright © 2011-2022 走看看