← 返回目录

模块化

第 95 / 154 卷日期:

p.a = 2 // 监听到属性a改变 p.a // 'a' = 2

自定义set和get函数,在原本逻辑中插入函数逻辑,实现在对对象任何属性进行读写时发出通知

如果是实现Vue中的响应式,需要在get中收集依赖,在set派发更新,Vue3.0使用Proxy代替原来API的原因在于 Proxy无需一层层递归为每个属性添加代理,一次即可完成以上操作,性能更好,Proxy可以完美监听到任何方式

的数据改变,缺陷是浏览器兼容性不太好

模块化

特点

  1. 解决命名污染,全局污染,变量冲突等
  2. 内聚私有,变量不能被外部访问
  3. 更好的分离,按需加载
  4. 引入其他模块可能存在循环引用问题
  5. 代码抽象,封装,复用和管理
  6. 避免通过script标签从上至下加载资源
  7. 大型项目资源难以维护,特别是多人合作的情况

CommonJS

服务端解决方案。加载速度快(因为模块文件一般存在本地硬盘)

每个文件是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。

运行时加载,只能在运行时才能确定一些东⻄ 同步加载,只有加载完成后,才能执行后续操作。因为用于服务端,文件都在本地,同步导入即使卡住主线

程影响也不大。

导出时都是值拷贝,就算导出的值变了,导入的值也不会改变,所以如果想更新值,必须重新导入一次。

模块在首次执行后会缓存,再次加载只返回缓存结果,若想再次执行,可清除缓存。

模块加载的顺序就是代码出现的顺序

基本语法

暴露模块:module.exports = value或exports.xxx = value 引入模块:require(xxx),如果是第三方模块,xxx为模块名;如果是自定义模块,xxx为模块文件路径

CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即 module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

// 加载模块 var example = require('./example.js');

var config = require('config.js');

var http = require('http');

...

}

module.exports = function(x){

console.log(x)

}

exports.xxx=value;

require命令用于加载模块文件。require命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的 exports对象。如果没有发现指定模块,会报错。

因为nodejs主要用于服务器编程,模块文件一般已经存在本地硬盘,所以加载起来比较快,不用考虑异步加载的方式,所以使用CommonJS规范。

如果是浏览器环境,要从服务器端加载模块,用CommonJS需要等模块下载完并运行后才能使用,将阻塞后面代码的执行,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范,解决异步加载的问题。

AMD

会编译成 require/exports 来执行

浏览器一般使用AMD规范,解决异步加载问题。

RequireJS是一个工具库。主要用于客户端的模块管理。它可以让客户端的代码分成一个个模块,实现异步或动态加载,从而提高代码的性能和可维护性。它的模块管理遵守AMD规范。

Require.js的基本思想是,通过define方法,将代码定义为模块;通过require方法,实现代码的模块加载。

基本语法

定义暴露模块:

//定义没有依赖的模块 define(function(){

return 模块

})

//定义有依赖的模块 define(['module1', 'module2'], function(m1, m2){

return 模块

})

require(['module1', 'module2'], function(m1, m2){

使用m1/m2

})

采用异步加载的方式来加载模块,模块的加载不影响后面语句的执行,所有依赖这个模块的语句都定义在一个回调函数里,等到加载完成后再执行回调函数;也可以根据需要动态加载模块

AMD模块定义的方法非常清晰,不会污染全局环境,可清楚地显示依赖关系

CMD

CMD规范专门用于浏览器端,异步加载模块,实用模块时才会加载执行。

整个了CommonJS和AMD规范的特点。

Sea.js中,所有JS模块都遵循CMD模块定义规范。

基本语法

定义暴露模块:

//定义没有依赖的模块 define(function(require, exports, module){

exports.xxx = value module.exports = value

})

//定义有依赖的模块 define(function(require, exports, module){

//引入依赖模块(同步)

var module2 = require('./module2')

//引入依赖模块(异步)

require.async('./module3', function (m3) { })

//暴露模块 exports.xxx = value

})

引入使用模块:

var m1 = require('./module1')

var m4 = require('./module4')

m1.show()

m4.show()

})

ES6

使用 import 和 export 的形式来导入导出模块。这种方案和上面三种方案都不同。

思想是尽量静态化,为了保证在编译时就能确定模块的依赖关系和输入输出的变量。

异步导入,因为用于浏览器,需要下载文件,如果采用同步导入会对渲染有很大影响

采用实时绑定的方式,导入导出的值都指向同一个内存地址,所以导入值会跟随导出值变化

会编译成 require/exports 来执行

使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。

一个模块就是一个独立的文件,该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。

在编译阶段,import会提升到整个模块的头部,首先执行。

如果不需要知道变量名或函数就完成加载,就要用到export default命令,为模块指定默认输出。

export default命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此export default命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应export default命令。

基本语法

export

1.如果不想对外暴露内部变量的真实名称,可以使用as关键字设置别名,同一个属性可以设置多个别名。

在外部进行引入时,可以通过name2这个变量访问到king值。

const name='king';

export {name as name2};

2.在同一个文件中,同一个变量名只能够export一次,否则会抛出异常。

const _name='king';

export {name as _name};

export {name};//抛出异常,name作为对外输出的变量,只能export一次

import

1.import和export的变量名相同

2.相同变量名的值只能import一次

3.import命令具有提升的效果

//export.js export const name='king';

//import.js console.log(name);//king

import {name} from './export.js'

本质:因为import是在编译期间运行的,在执行console语句之前就已经执行了import语句。因此能够打印出 name的值,即,King

4.多次import时,只会加载一次

以下代码汇总,我们import了两次export.js文件,但是最终只输出执行了一次“开始执行”,可以推断出import导入的模块是个单例模式。

//export.js console.log('start');

export const name='king';

export const age=19;

//import.js import {name} from './export.js

import {age} from './export.js''

5.允许我们在需要的时候才动态加载模块,而不是一开始就加载所有模块,这样可以帮我们提高性能。

这个新功能允许我们将import()作为函数调用,将其作为参数传递给模块的路径。它返回一个 promise,它用一个模块对象来实现,可以访问该对象的导出。

全站分卷索引 · 154 卷
  1. 1代码随想录知识星球精华(最强八股文)第五版(前端篇))
  2. 2html语义化
  3. 3src 和 href 的区别
  4. 4link 与 @import 的区别
  5. 5iframe
  6. 6CSS
  7. 7伪元素和伪类
  8. 8block,inline,inline-block
  9. 9重排、重绘和合成
  10. 10盒子模型
  11. 11margin 合并
  12. 12margin和padding 的值为百分比时
  13. 13浮动
  14. 14定位
  15. 15CSS选择器
  16. 16CSS选择器优先级
  17. 17选择器权重Specificity
  18. 18CSS属性继承
  19. 19不可/可继承属性
  20. 20display: none与 visibility: hidden的区别
  21. 21background-size
  22. 22client、offset&scroll
  23. 23CSS3新特性
  24. 24flex布局
  25. 25常见布局
  26. 26三栏布局
  27. 27垂直居中
  28. 28水平垂直居中
  29. 29CSS画三角形
  30. 30使chrome支持12px以下文字
  31. 31响应式布局
  32. 32媒体查询
  33. 33过渡与动画
  34. 34JavaScript 动画 和 CSS动画
  35. 35SCSS
  36. 36CSS性能优化
  37. 37有哪些数据类型
  38. 38判断数据类型
  39. 39类型转换
  40. 40parseInt&parseFloat
  41. 41浮点数求和步骤
  42. 42十进制小数转二进制
  43. 430.1+0.2 为什么不等于 0.3
  44. 44undefined 和 undeclared 的区别
  45. 45JavaScript NaN 属性
  46. 46isFinite()&isNaN()
  47. 47数组
  48. 48对原数组有影响
  49. 49对原数组无影响
  50. 50数组去重
  51. 51数组拍平
  52. 52ES6新增的数组方法
  53. 53判断是否存在某个值
  54. 54arguments为啥不是数组
  55. 55对象
  56. 56遍历对象的方法
  57. 57判断对象是否具有属性
  58. 58for in 和 for of 的区别
  59. 59继承方式
  60. 60instanceof
  61. 61深浅拷贝
  62. 62freeze属性
  63. 63函数
  64. 64函数柯里化
  65. 65函数的 length
  66. 66箭头函数和普通函数区别
  67. 67构造函数
  68. 68执行上下文
  69. 69作用域
  70. 70作用域和作用域链
  71. 71闭包和内存泄漏
  72. 72this
  73. 73关于 this 的指向问题
  74. 74改变this指向的方法(bind / call / apply)
  75. 75字符串
  76. 76DOM和事件
  77. 77哪些事件支持冒泡
  78. 78阻止冒泡
  79. 79HTMLCollection、NodeList
  80. 80dom.onclick 和 dom.addEventListener的区别
  81. 81e.target和e.currentTarget
  82. 82页面生命周期
  83. 83异步
  84. 84内存管理GC
  85. 85其它
  86. 86JavaScript 中日期时间格式转换
  87. 87input和object实现双向绑定
  88. 88JSON.stringify()
  89. 89escape、encodeURI&encodeURIComponent
  90. 90移动端滚动穿透和溢出
  91. 91ES6
  92. 92Map字典
  93. 93... 与rest
  94. 94proxy
  95. 95模块化
  96. 96Ajax、Fetch和Axios
  97. 97Webpack
  98. 98浏览器:事件循环
  99. 99浏览器内核
  100. 100浏览器同源策略
  101. 101输入URL回车后发生了什么
  102. 102HTTP
  103. 103HTTP 2.0
  104. 104浏览器存储
  105. 105鉴权
  106. 106Webstorage
  107. 107浏览器执行机制
  108. 108AST 抽象语法树
  109. 109性能优化
  110. 110CSS
  111. 111网络相关
  112. 112使用HTTP2.0
  113. 113图片
  114. 114CDN图片
  115. 115其他文件优化
  116. 116降低APP首页开屏渲染时间
  117. 117页面白屏
  118. 118HTTPS中间人攻击
  119. 119Web Worker
  120. 120Service Worker
  121. 121微前端
  122. 122Vue
  123. 123v-show 和 v-if 的区别
  124. 124双向数据绑定的原理
  125. 125Vue中的插槽使用
  126. 126Vue中的key
  127. 127Vue过滤器
  128. 128Vue中Scoped原理
  129. 129Vue中$nextTick的使用
  130. 130Vue中实现组件通信的方式
  131. 131Vue-router
  132. 132Vue路由传参
  133. 133前端路由
  134. 134Vuex
  135. 135虚拟DOM
  136. 136DIFF 算法
  137. 137Vue3和Vue2有哪些区别
  138. 138说一说你对React的理解
  139. 139React事件机制
  140. 140说一说你对react refs的理解
  141. 141react中key的作用
  142. 142组件开发
  143. 143有状态组件和无状态组件
  144. 144函数式组件和类组件的区别
  145. 145PureComponent&Component
  146. 146常见 Hooks
  147. 147状态管理
  148. 148redux toolkit
  149. 149React18新特性
  150. 150client中的createRoot取代以前的ReactDOM.render
  151. 151Suspense
  152. 152新的Hooks
  153. 153VDom一定更快吗
  154. 154Fiber