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