• js模块化——commonJS


    总结于知乎《前端科普系列-CommonJS:不是前端却革命了前端》,作者:无名之辈

    What

    为了解决模块化问题,而制定的一种模块化规范

    规范核心部分:

    1. Node.js 应用由模块组成,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
    // a.js
    var name = 'morrain'
    var age = 18
    

    上面代码中,a.js 是 Node.js 应用中的一个模块,里面申明的变量 name 和 age 是 a.js 私有的,其它文件都访问不到。
    2. 每个模块内部有两个变量可以使用,require 和 module。

    require 用来加载某个模块

    module 代表当前模块,是一个对象,保存了当前模块的信息。exports 是 module 上的一个属性,保存了当前模块要导出的接口或者变量,使用 require 加载的某个模块获取到的值就是那个模块使用 exports 导出的值

    // a.js
    var name = 'morrain'
    var age = 18
    module.exports.name = name
    module.exports.getAge = function(){
        return age
    }
    
    //b.js
    var a = require('a.js')
    console.log(a.name) // 'morrain'
    console.log(a.getAge())// 18
    

    HOW

    1. 关于export
      为了方便,Node.js 在实现 CommonJS 规范时,为每个模块提供一个 exports的私有变量,指向 module.exports。你可以理解为 Node.js 在每个模块开始的地方,添加了如下这行代码。
      var exports = module.exports
      于是上面的代码也可以这样写:
    // a.js
    var name = 'morrain'
    var age = 18
    exports.name = name
    exports.getAge = function(){
        return age
    }
    

    如果一个模块的对外接口,就是一个单一的值,可以使用 module.exports 导出

    // a.js
    var name = 'morrain'
    var age = 18
    module.exports = name
    
    1. 关于require
      require 命令的基本功能是,读入并执行一个 js 文件,然后返回该模块的 exports 对象的拷贝。如果没有发现指定模块,会报错。
      2.1 NodeJs 会缓存一个module

      如图所示,第二次require的时候,并没有重新执行并加载module A,而是直接返回了第一次 require 时的结果,也就是模块A的 module.exports。
      2.2 require 的是被导出的值的拷贝。也就是说,一旦导出一个值,模块内部的变化就影响不到这个值 。
    // a.js
    var name = 'morrain'
    var age = 18
    exports.name = name
    exports.age = age
    exports.setAge = function(a){
        age = a
    }
    // b.js
    var a = require('a.js')
    console.log(a.age) // 18
    a.setAge(19)
    console.log(a.age) // 18
    

    CommonJS 的实现

    有了commonjs的规范,我们可以将它在前端/后端进行实现:

    commonjs在前端的实现:

    Browserify 、Webpack就是将各模块代码进行打包,进而转化为浏览器能够运行的js代码。commonjs规范无非是三个东西,module、require和exports,webpack等打包工具将其实现后,就可以进行转化了:

    // bundle.js
    (function (modules) {
        // 模块管理的实现
    })({
      'a.js': function (module, exports, require) {
        // a.js 文件内容
      },
      'b.js': function (module, exports, require) {
        // b.js 文件内容
      },
      'index.js': function (module, exports, require) {
        // index.js 文件内容
      }
    })
    

    ** 但是前端有一个异步加载的问题,因为各个模块不一定同时下载完成 **
    为了解决这个问题,后面发展起来了众多的前端模块化规范,包括 CommonJS 大致有如下几种:

    现在大都使用的是ES6 Module了,内容也不用多说,就是import,export, export default, import()等

    ES6 Module 和 CommonJS 的区别

    1. 执行时加载和编译时加载
      CommonJS 只能在运行时确定导出的接口,实际导出的就是一个对象。而 ES6 Module 的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及导入和导出的变量,也就是所谓的"编译时加载"。

    正因为如此,import 命令具有提升效果,会提升到整个模块的头部,首先执行。下面的代码是合法的,因为 import 的执行早于 getAge 的调用。

    // a.js
    export const name = 'morrain'
    const age = 18
    export function getAge () {
        return age
    }
    
    // b.js
    const age = getAge()
    console.log(age) // 18
    import { getAge } from 'a.js'
    
    1. 没有拷贝或者cache
      由于编译过后代码已经被拼接在一起,所以不会有对被require文件的缓存。所以对被引模块进行内部方法修改变量后,能够反映到后续程序执行中。
    // a.js
    var name = 'morrain'
    var age = 18
    const setAge = a => age = a
    export {
        name,
        age,
        setAge
    }
    
    // b.js
    import * as a from 'a.js'
    
    console.log(a.age) // 18
    a.setAge(19)
    console.log(a.age) // 19
    
  • 相关阅读:
    jmeter_响应断言与xpath assertion
    jmeter查看结果树_各种方式
    HTTP request/respond详解及响应状态码
    LINUX常用命令笔记1
    什么是接口以及接口测试
    jmeter关联——正则表达式笔记
    BeautifulReport报告
    小白笔记:Git入门之常见命令
    Apache+Php+Mysql配置
    linux搭建jenkins+github详细步骤
  • 原文地址:https://www.cnblogs.com/lyzz1314/p/15693373.html
Copyright © 2020-2023  润新知