首页 > 其他分享 >JS模块化—CJS&AMD&CMD&ES6-前端面试知识点查漏补缺

JS模块化—CJS&AMD&CMD&ES6-前端面试知识点查漏补缺

时间:2022-10-10 08:55:59浏览次数:95  
标签:count 知识点 查漏 const ES6 require increase dependencyModule1 加载

本文从以时间为轴从以下几个方面进行总结JS模块化。从无模块化 => IIFE => CJS => AMD => CMD => ES6 => webpack这几个阶段进行分析。

历史

幼年期:无模块化

方式

  1. 需要在页面中加载不同的js,用于动画,组件,格式化
  2. 多种js文件被分在了不同的文件中
  3. 不同的文件被同一个模板所引用
<script src="jquery.js"></script>
<script src="main.js"></script>
<script src="dep1.js"></script>

此处写法文件拆分是最基础的模块化(第一步)

* 面试中的追问

script标签的参数:async & defer

<script src="jquery.js" async></script>

总结

  • 三种加载
  1. 普通加载:解析到立即阻塞,立刻下载执行当前script
  2. defer加载:解析到标签开始异步加载,在后台下载加载js,解析完成之后才会去加载执行js中的内容,不阻塞渲染
  3. async加载:(立即执行)解析到标签开始异步加载,下载完成后开始执行并阻塞渲染,执行完成后继续渲染

image.png

  • 兼容性:> IE9

  • 问题可能被引导到 => 1. 浏览器的渲染原理 2.同步异步原理 3.模块化加载原理

  • 出现的问题

  1. 污染全局作用域

成长期(模块化前夜) - IIFE(语法测的优化)

image.png

作用域的把控

let count = 0;
const increase = () => ++count;
const reset = () => {
    count = 0;
}

利用函数的块级作用域

(() => {
    let count = 0;
    ...
})
//最基础的部分

实现一个最简单的模块

const iifeModule = (() => {
    let count = 0;
    const increase = () => ++count;
    const reset = () => {
        count = 0;
    }
    console.log(count);
    increase();
})();

  • 追问:独立模块本身的额外依赖如何优化

优化1:依赖其他模块的传参型

const iifeModule = ((dependencyModule1,dependencyModule2) => {
    let count = 0;
    const increase = () => ++count;
    const reset = () => {
        count = 0;
    }
    console.log(count);
    increase();
    ...//可以处理依赖中的方法
})(dependencyModule1,dependencyModule2)

面试1:了解jquery或者其他很多开源框架的模块加载方案

将本身的方法暴露出去

const iifeModule = ((dependencyModule1,dependencyModule2) => {
    let count = 0;
    const increase = () => ++count;
    const reset = () => {
        count = 0;
    }
    console.log(count);
    increase();
    ...//可以处理依赖中的方法
    return 
        increase,reset
    }
})(dependencyModule1,dependencyModule2)
iifeModule.increase()

=> 揭示模式 revealing => 上层无需了解底层实现,仅关注抽象 => 框架

  • 追问:
  1. 继续模块化横向展开
  2. 转向框架:jquery|vue|react模块细节
  3. 转向设计模式

成熟期

image.png

CJS (Commonjs)

node.js指定

特征:

  1. 通过module + exports对外暴露接口
  2. 通过require去引入外部模块,参考 前端进阶面试题详细解答

main.js

const dependencyModule1 = require('./dependencyModule1')
const dependencyModule2 = require('./dependencyModule2')

let count = 0;
const increase = () => ++count;
const reset = () => {
    count = 0;
}
console.log(count);
increase();

exports.increase = increase;
exports.reset = reset;

module.exports = {
    increase, reset
}

exe

const {increase, reset} = require(./main.js)

复合使用

(function(this.value,exports,require,module){
    const dependencyModule1 = require('./dependencyModule1')
    const dependencyModule2 = require('./dependencyModule2')
}).call(this.value,exports,require,module)

追问:一些开源项目为何要把全局、指针以及框架本身作为参数

(function(window,$,undefined){
    const _show = function(){
        $("#app").val("hi zhuawa")
    }
    window.webShow = _show;
})(window,jQuery)

阻断思路

  • 一. window

    1. 全局作用域转换为局部作用域,window是全局作用域,如果不转成局部作用域会有一个向上查找知道全局的过程,提升执行效率
    2. 编译时优化:编译后会变成(优化压缩成本,销毁)
    (function(c){})(window) // window会被优化成c
    //window在里面所有别的执行所有的变化都会随着执行完毕都会跟着c一起被销毁
    
    
  • 二. jquery

    1. 独立定制复写和挂载
    2. 防止全局串扰
  • 三. undefined
    防止改写:在执行内部这段代码的时候保证undefined是正确的,不会被改写,如在外部定义一个undefined =1
    undefined对jquery本身是一个很重要的一个存在

优缺点

  • 优点:CommonJS率先在服务端实现了,从框架层面解决了依赖,全局变量未然的问题
  • 缺点: 针对服务端的解决方案,异步拉取,依赖处理不是很友好

=> 异步依赖的处理

AMD

通过异步执行 + 允许指定回调函数
经典实现框架:require.js

新增定义方式:

//define来定义模块
define(id, [depends], callback)
//require来进行加载
reuqire([module],callback)

模块定义的地方

define('amdModule',[dependencyModule1,dependencyModule2],(dependencyModule1,dependencyModule2) => {
    //业务逻辑
    let count = 0;
    const increase = () => ++count;
    module.exports = {
        increase
    }
})

引入的地方

require(['amdModule'],amdModule => {
    amdModule.increase()
})

面试题:如果在AMDModule中想兼容已有代码,怎么办?

define('amdModule',[],require => {
    const dependencyModule1 = require('./dependencyModule1')
    const dependencyModule2 = require('./dependencyModule2')
    //业务逻辑
    let count = 0;
    const increase = () => ++count;
    module.exports = {
        increase
    }
})

面试题:手写兼容CJS&AMD

//判断的关键:
    1. object还是function
    2. exports ?
    3. define

(define('AMDModule'),[],(require,export,module) => {
    const dependencyModule1 = require('./dependencyModule1')
    const dependencyModule2 = require('./dependencyModule2')

    let count = 0;
    const increase = () => ++count;
    const reset = () => {
        count = 0;
    }
    console.log(count);
    export.increase = increase();
})(
    //目标:一次性区分CJS还是AMD
    typeof module === 'object' && module.exports && typeof define !== function ? //CJS
    factory => module.exports = factory(require,exports,module)
    : //AMD
    define
)

优缺点

  • 优点:适合在浏览器中加载异步模块的方案
  • 缺点:引入成本

CMD

按需加载
主要应用框架:sea.js

define('module',(require,exports,module) => {
    let $ = require('jquery')
    let dependencyModule1 = require('./dependencyModule1')
})

优缺点

  • 优点:按需加载,依赖就近
  • 缺点:依赖打包,加载逻辑存在于每个模块中,扩大了模块体积,同时功能上依赖编译

ES6模块化

新增定义:

  • 引入:import
  • 引出:export

面试:

  1. 性能 - 按需加载
// ES11原生解决方案
import('./esMModule.js').then(dynamicModule => {
    dynamicModule.increase();
})

优点:
通过一种统一各端的形态,整合了js模块化的方案
缺点:本质上还是运行时分析

解决模块化新思路 - 前端工程化

遗留

根本问题:运行时进行依赖分析
解决方案:线下执行

编译时依赖处理思路

<script src="main.js"></script>
<script>
  // 给构建工具一个标识位
  require.config(__FRAME_CONFIG__);
</script>
<script>
  require(['a', 'e'], () => {    // 业务逻辑
  })
</script>

define('a', () => {
    let b = require('b')
    let c = require('c')
})

完全体:webpack为核心的前端工程化 + mvvm框架的组件化 + 设计模式

标签:count,知识点,查漏,const,ES6,require,increase,dependencyModule1,加载
From: https://www.cnblogs.com/loveX001/p/16774394.html

相关文章

  • 文件相关知识点及函数基本知识点
    文件相关知识点及函数基本知识点目录文件相关知识点及函数基本知识点一、文件读写总概括二、计算机硬盘修改数据的原理(了解)三、文件内容修改(了解)四、函数简介五、函数语法......
  • mysql 知识点 最完整的 思维导图
     下边的文章是我遇到的 总结sql知识点,并且做成了思维导图做的非常全的。推荐大家点击看。​ 还有一篇是 mysql 基础的sql语句的 思维导图,也很不错。​  常用的sql......
  • let、const命令(学习阮一峰ES6记录)
    1.let命令ES6新增let命令,作用和var类似,用来声明变量,但是let只能在所在代码块(区域)中使用。例:1{2leta=2;3varb=3;4}5console.log(a)//aisn......
  • 面试知识点整理
    1.volatile关键字 volatile是jvm的轻量级的同步锁保证可见性不保证原子性禁止指令重排2.JMM(内存模型)可见原子有序可见性的体现。3.CAS compare and set 比较并交换,这......
  • 探索ES6(ES2015)
    探索ES6(ES2015)本书HTML在线:ExploringES6https://exploringjs.com/es6/index.html是一本关于ECMA-2626thEdition(ECMAScript2015)的最全面的书。是一本为已经了解J......
  • es6 中文
    https://m.w3cschool.cn/escript6/escript6-cx4337fr.htmlhttps://es6-org.github.io/exploring-es6/#./16.7.mdhttps://w3ctech.com/topic/2045......
  • es6
    entries(),keys()和values()用户遍历数组,它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历;values()是对键值的遍历;entries......
  • C语言新知识点:枚举变量enum
    我们可以定义一个变量,然后进行判断inta;if(a==1){}else{}但上面的方式导致变量以数值方式表示,晦涩难懂可以考虑用宏定义#defineYes1但是当范围不同......
  • JSP快速上手与MVC模式和三层架构的知识点总结+综合案例
    阅读提示:说明由于JSP实在是太难读难写复杂占资源难调试不分离了,拉跨!(节目效果哈,勿喷),作为一种有(ji)更(hu)好(jiu)的(yao)上(bei)位(tao)替(tai)代(le)的技术,本着为了体现新技......
  • es6 模块化
    ES6InDepth是一系列关于ECMAScript标准第6版(简称ES6)中JavaScript编程语言新增功能的文章。不久之前,JavaScript的主要用途是表单验证,可以肯定的是,您的平均<input-onchang......