zoukankan      html  css  js  c++  java
  • JS通用模块写法

    模块化这个问题并非一开始就存在,WWW刚刚问世的时候,html,JavaScript,CSS(JS和CSS都是后来在网景被引进浏览器的)都是极其简单的存在,不需要模块化。

    模块化的需求是规模的产物,当web page进化到web application,浏览器端处理的逻辑越来越复杂,展现的样式和动画越来多,对于工程的要求也就越来越高。于是模块化的需求也就产生了。模块化的意义:

    • 组件的复用,降低开发成本和维护成本
    • 组件单独开发,方便分工合作
    • 模块化遵循标准,方便自动化依赖管理,代码优化,部署

    JavaScript长久以来被认为是简单的脚本语言,实际上情况早就发生来变化,在最新版的ECMA-262(ES6)文档中强调JavaScript是通用编程语言而不是脚本语言。脚本语言,比如shell并不是用来完成复杂功能的,只是用来做一些自动化控制,是不需要模块化的。而用于构建复杂系统通用编程语言(比如Java)一般都有模块的实现。

    在ES6以前,JS语言没有模块化,如何让JS不止运行在浏览器,且能更有效的管理代码,

    于是应运而生CommonJS这种规范,定义了三个全局变量:

    require,exports,module
    

    require 用于引入一个模块

    exports 对外暴露模块的接口,可以是任何类型

    module 是这个模块本身的对象

    用require引入时获取的是这个模块对外暴露的接口(exports)

    Node.js 使用了CommonJS规范:

    var foo = require('foo')
    var out = foo.sayName()
    module.exports = out
    

    在浏览器端,不像Node.js内部支持CommonJS,如何进行模块化,

    于是出现了 CMD 与 AMD 两种方式,其主要代表是 seajs 和 requirejs,

    他们都定义了一个全局函数 define 来创建一个模块:

    //CMD
    define(function(require,exports,module){
      var foo = require('foo')
      var out = foo.sayName()
      module.exports = out
    })
    
    //AMD
    define(['foo'],function(foo){
     var out = foo.sayName()
     return out;
    })
    

    可以看出CMD完好的保留了CommonJS的风格,

    而AMD用了一种更简洁的依赖注入和函数返回的方式实现模块化。

    两者除风格不同外最大区别在于加载依赖模块的方式,

    CMD是懒加载,在require时才会加载依赖,

    而AMD是预加载,在定义模块时就提前加载好所有依赖。

    我们要实现一个模块,让它既能在seajs(CMD)环境里引入,又能在requirejs(AMD)环境中引入,当然也能在Node.js(CommonJS)中使用,另外还可以在没有模块化的环境中用script标签全局引入.

    首先搞一个模块

    var factory = function(){
      var moduleName = {}
      return moduleName
    }
    

    当然 return 输出的可以是任何值,对象,类,其他都可以

    首先满足Node.js 或者 ES6,我们可以通过全局变量module 和 exports 来判断

    var factory = function(){
      var moduleName = {}
      return moduleName
    }
    if(typeof module !=='undefined' && typeof exports ==='object'){
      module.exports = factory
    }
    

    在CMD和AMD 中,我们需要提供一个工厂函数传入define来定义模块,当没有上述全局变量,且有define全局变量时,我们认为是AMD或CMD,可以直接将factory传入define:

    var factory = function(){
      var moduleName = {}
      return moduleName
    }
    if(typeof module !=='undefined' && typeof exports ==='object'){
      module.exports = factory
    }else if(typeof define ==='function' && (define.cmd || define.amd)){
      define(factory)
    } 
    

    注意:CMD其实也支持return返回模块接口,所以两者可以通用。

    然后还要满足script标签全局引入,我们可以将模块放在window上,为了模块内部在浏览器和Node.js中都能使用全局对象,我们可以做此判断:

    var global = typeof window !== 'undefined' ? window : global;
    

    我们用一个立刻执行的闭包函数将所有代码包含,来避免污染全局空间,并将global对象传入闭包函数,最终变成这样:

    ;(function(global){
      var factory = function(){
        var moduleName = {}
        return moduleName
      }
      if(typeof module !=='undefined' && typeof exports ==='object'){
        module.exports = factory
      }else if(typeof define ==='function' && (define.cmd || define.amd)){
        define(factory)
      }else{
        global.factory = factory
      }
    })(typeof window !== 'undefined' ? window : global);
    

    注意:闭包前加上分号是为了给前一个模块填坑,分号多了没问题,少了则语句可能发生变化。

    然后,就能愉快的调用了

    //Node.js
    var myModule = require('moduleName')
    
    //Seajs
    define(function(require,exports,module){
      var myModule = require('moduleName')
    })
    
    // Browser global
    <script src='moduleName.js'></script>
    

    [完]

  • 相关阅读:
    学习进度表
    第八次日志
    第七次日志
    第六次日志
    第五次日志
    第四次日志
    第一次日志
    第三次日志
    第二次日志
    学习进度表
  • 原文地址:https://www.cnblogs.com/chuchur/p/10462291.html
Copyright © 2011-2022 走看看