专栏首页前端QJS模块化规范总结(面试必备良药)

JS模块化规范总结(面试必备良药)

文章说明

本文为我之前总结的笔记,因为内容在面试中问得比较多,因而搬运过来,作为面试系列的文章之一。

简介

规范JavaScript的模块定义和加载机制,降低了学习和使用各种框架的门槛,能够以一种统一的方式去定义和使用模块,提高开发效率,降低了应用维护成本。 模块化解决的问题:

  • 命名冲突
  • 文件依赖

commonJS

1、模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。 2、模块加载会阻塞接下来代码的执行,需要等到模块加载完成才能继续执行——同步加载。

适用场景:服务器环境,nodejs的模块规范是参照commonJS实现的。

用法:

1、导入:require('路径') 2、导出:module.exports和exports

// a.js
// 相当于这里还有一行:var exports = module.exports;代码
exports.a = 'Hello world';  // 相当于:module.exports.a = 'Hello world';

// b.js
var moduleA = require('./a.js');
console.log(moduleA.a);     // 打印出hello world

注意:module.exports和exports的区别是exports只是对module.exports的一个引用,相当于Node为每个模块提供一个exports变量,指向module.exports。这等同在每个模块头部,有一行var exports = module.exports;这样的命令。

AMD

1、异步加载 2、管理模块之间的依赖性,便于代码的编写和维护。

适用场景:浏览器环境,requireJS是参照AMD规范实现的

用法: 1、导入:require(['模块名称'], function ('模块变量引用'){// 代码}); 2、导出:define(function (){return '值');

// a.js
define(function (){
  return {
   a:'hello world'
  }
});
// b.js
require(['./a.js'], function (moduleA){
    console.log(moduleA.a); // 打印出:hello world
});

CMD

1、CMD是在AMD基础上改进的一种规范,和AMD不同在于对依赖模块的执行时机处理不同,CMD是就近依赖,而AMD是前置依赖。

适用场景:浏览器环境,seajs是参照CMD规范实现的,requireJS的最新的几个版本也是部分参照了CMD规范的实现。

用法:

1、导入:define(function(require, exports, module) {}); 2、导出:define(function (){return '值');

// a.js
define(function (require, exports, module){
  exports.a = 'hello world';
});
// b.js
define(function (require, exports, module){
    var moduleA = require('./a.js');
    console.log(moduleA.a); // 打印出:hello world
});

AMD与CMD区别

最明显的区别就是在模块定义时对依赖的处理不同

  1. AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
  2. CMD推崇就近依赖,只有在用到某个模块的时候再去require

AMD和CMD最大的区别是对依赖模块的执行时机处理不同

很多人说requireJS是异步加载模块,SeaJS是同步加载模块,这么理解实际上是不准确的,其实加载模块都是异步的,只不过AMD依赖前置,js可以方便知道依赖模块是谁,立即加载,而CMD就近依赖,需要使用时把模块变为字符串解析一遍才知道依赖了那些模块,这也是很多人诟病CMD的一点,牺牲性能来带来开发的便利性,实际上解析模块用的时间短到可以忽略

为什么我们说两个的区别是依赖模块执行时机不同,为什么很多人认为ADM是异步的,CMD是同步的(除了名字的原因。。。)

同样都是异步加载模块,AMD在加载模块完成后就会执行改模块,所有模块都加载执行完后会进入require的回调函数,执行主逻辑,这样的效果就是依赖模块的执行顺序和书写顺序不一定一致,看网络速度,哪个先下载下来,哪个先执行,但是主逻辑一定在所有依赖加载完成后才执行

CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的

这也是很多人说AMD用户体验好,因为没有延迟,依赖模块提前执行了,CMD性能好,因为只有用户需要的时候才执行的原因

UMD

1、兼容AMD和commonJS规范的同时,还兼容全局引用的方式。

适用场景:浏览器或服务器环境

用法:

无导入导出规范,只有如下的一个常规写法:

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        //AMD
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        //Node, CommonJS之类的
        module.exports = factory(require('jquery'));
    } else {
        //浏览器全局变量(root 即 window)
        root.returnExports = factory(root.jQuery);
    }
}(this, function ($) {
    //方法
    function myFunc(){};
    //暴露公共方法
    return myFunc;
}));

ESM(ES6 Module)

1、按需加载(编译时加载) 2、import和export命令只能在模块的顶层,不能在代码块之中(如:if语句中),import()语句可以在代码块中实现异步动态按需动态加载

适用场景:浏览器或服务器环境(以后可能支持)

用法:

1、导入:import {模块名A,模块名B…} from '模块路径' 2、导出:export和export default 3、import('模块路径').then()方法

/*错误的写法*/
// 写法一
export 1;

// 写法二
var m = 1;
export m;

// 写法三
if (x === 2) {
  import MyModual from './myModual';
}

/*正确的三种写法*/
// 写法一
export var m = 1;

// 写法二
var m = 1;
export {m};

// 写法三
var n = 1;
export {n as m};

// 写法四
var n = 1;
export default n;

// 写法五
if (true) {
    import('./myModule.js')
    .then(({export1, export2}) => {
      // ...·
    });
}

// 写法六
Promise.all([
  import('./module1.js'),
  import('./module2.js'),
  import('./module3.js'),
])
.then(([module1, module2, module3]) => {
   ···
});

注意:export只支持对象形式导出,不支持值的导出,export default命令用于指定模块的默认输出,只支持值导出,但是只能指定一个,本质上它就是输出一个叫做default的变量或方法。

本文分享自微信公众号 - 前端Q(luckyWinty)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 移动端图片上传旋转、压缩的解决方案

    在手机上通过网页 input 标签拍照上传图片,有一些手机会出现图片旋转了90度的问题,包括 iPhone 和个别三星手机。这些手机竖着拍的时候才会出现这种问题...

    IMWeb前端团队
  • 谁说你只是"会用"jQuery?

    前端在最近几年实在火爆异常,vue、react、angular各路框架层出不穷,咱们要是不知道个双向数据绑定,不晓得啥是虚拟DOM,也许就被鄙视了。火热的背后往...

    IMWeb前端团队
  • Zepto核心模块之工具方法拾遗

    用了document.documentElement.contains做判断,如果浏览器支持该方法,就用node.contains重新包了一层得到一个函数,差别...

    IMWeb前端团队
  • 给 Number 打 Call

    最近“打 call”这个词突然流行起来,我想到 call 在 JavaScript中可是个重要的方法,那么能不能用 JavaScript也来玩一把打 call ...

    IMWeb前端团队
  • 优化 Webpack 构建结果

    Webpack应该是当下流行度最广的JavaScript构建、打包工具了。我们团队中大部分项目也在使用Webpack构建。项目的是传统的非SPA页面,我们使用了...

    IMWeb前端团队
  • xss漏洞挖掘思路

    xss作为江湖上一种常见的攻击手段,一直有广泛的使用。然而怎么样发现一个交互的地方是否会有xss漏洞呢?有一些通用的思路。一下就是思路的总结。

    IMWeb前端团队
  • 通过Scope Hoisting优化Webpack输出

    Scope Hoisting 可以让 Webpack 打包出来的代码文件更小、运行的更快, 它又译作 "作用域提升",是在 Webpack3 中新推出的功能。 ...

    IMWeb前端团队
  • 这些Zepto中实用的方法集

    这里先将$.fn.concat理解成原生数组的concat方法,我们会发现,其实他只能铺平一层。例如

    IMWeb前端团队
  • Unity内建图标

    Unity version: 2018.3.0f2 Icons what can load using EditorGUIUtility.IconContent

    bering
  • 利用whistle调试移动端页面

    whistle是基于Node实现的跨平台web调试代理工具,可以作为普通的http代理或者用来抓包、修改、操作http、https、websocket、tunn...

    IMWeb前端团队

扫码关注云+社区

领取腾讯云代金券