大纲
1. 堆栈内存和闭包作用域
- 堆栈内存及底层处理机制
- 玩转作用域和闭包机制
- 高阶编程技巧:柯里化函数、惰性函数、模块化开发、组合函数等
- jQuery & Lodash 源码解读
2. 面向对象程序设计
- 构造函数 & 原型 & 原型链 & Function VS Object
- 全面剖析 this 的五种情景及应用实战
- 全面解析js中的4种 数据类型检测 及方法封装
- call & apply & bind & instanceof & new 源码剖析
- jQuery & Lodash 源码解读
3. 深入浏览器的底层运行机制
- DOM树 & CSSDOM树 & RENDER树 & LAYOUT & 分层 & PAINTING
- CRP关键渲染路径和前端性能优化
- EventLoop & EventQueue & 微任务 & 宏任务
- 移动端白屏优化方案之骨架屏技术Skeleton
4. 事件 & 设计模式 & 插件组件封装
- 事件池机制 & 事件传播 & 事件代理
- 设计模式:观察者、发布订阅、单例、工厂、代理、装饰...
- 开源级插件组件封装
- jQuery & Lodash 源码解读
5. ES6核心知识和源码分析
- Promise和PromiseA+规范源码
- async & await 源码实现
- generator & iterator & Set & Map & WeakSet & WeakMap
- 模块化:AMD、CMD、CommonJS、ES6Module
- ES新特性解析
6. AJAX/HTTP前后端数据交互和网络通信
- HTTP & HTTPS & HTTP2.0 & DNS & TCP
- 基于HTTP网络层的前端性能优化汇总分析
- ajax & fetch & axios & 数据传输格式
- axios源码分析 & 二次配置封装
- 基于Promise封装自己的axios和fetch库
- N种跨域方案及底层原理剖析
第一讲:JS中的堆栈内存及函数底层处理机制
1. js中的数据类型
- 一、基本数据类型(值类型、原始类型)
- number
- NaN
- Infinity
- string
- boolean
- null
- undefined
- symbol 唯一值
- static Symbol
- Symbol.prototype
- bigint
- number
- 二、引用数据类型
- object
- 普通对象
- 数组对象
- 正则对象
- 日期对象
- JSON对象
- Set
- Map
- function
- 普通函数
- 构造函数
- 箭头函数
- 生成器函数
- object
typeof 10 => "number"
typeof NaN => "number"
typeof "" => "string"
typeof nul => "undefined" 暂时性死区 输入错误nul
typeof null => "object" // 000000 三零开头 object
typeof undefined => "undefined"
typeof Symbol() => "symbol"
typeof {} => "object"
typeof [] => "object" // => 都是object 不能细分对象
typeof /^$/ => "object"
typeof function(){} => "function"
/* 无穷大 */
Infinity === Infinity => true
/* 不是一个数字,都有可能,不能相等 */
NaN === NaN => false
/*
** 1. 用 isNaN()返回布尔值,检测是否有效数字
** 2. Object.is(NaN, NaN),检测两个值是否相等 => true
*/
1.1. typeof的原理
- 所有的数据类型值在计算机中存储的都是二进制
- null的二进制值是 000000
- 只要是对象,都是以 000 开始的
- typeof不能细分对象具体种类(数组,正则等)
- typeof检测时,是按照计算机存储的二进制值来检测的
- function不是以 000 开始的
1.2 Symbol() 唯一值
- 每运行一次都是唯一值,不是构造函数,不能被new
console.log(Symbol()) ==> Symbol()
// CC是标记
console.log(Symbol('CC')) ==> Symbol('CC')
// Symbol不能被new
console.log(new Symbol())
// Uncaught TypeError: Symbol is not a constructor
console.log(Symbol('AA') === Symbol('AA'))
// false 每次创建都是唯一值
let symb = Symbol('BB')
console.log(symb === symb) => true
-
用途:给对象设置唯一属性,在vuex/redux中做行为派发时,统一管理派发的行为标识,标识的值可以是唯一值
-
Symbol核心方法 dir(Symbol) 展开
Symbol.hasInstance
Symbol.toPrimitive
Symbol.toStringTag
Symbol.iterator
Symbol.isConcatSpreadable
Symbol.match
1.3 bigint 超大数字
- 最大安全数字:Number.MAX_SAFE_INTEGER
- 最小安全数字:Number.MIN_SAFE_INTEGER
- 2的60次方:Math.pow(2,60)
- 超过安全范围后面加n,数字后加n就是bigint
- typeof 9007199254740992000n => "bigint"
- 9007199254740992000n + 1n 可以计算
2. 栈内存Stack & 堆内存 Heap
-
数据类型的区别:堆内存和栈内存
-
基本概念
- declare->声明变量 & defined->关联变量和值
- ECStack: Execution Context Stack 执行环境栈
- EC: Execution Context 执行上下文
- VO: Varibale Object 变量对象
- GO: Global Object 全局对象
- 浏览器加载页面时,默认形成全局对象window,window指向全局对象,存放浏览器供JS调用的属性和方法,setTimeout等
2.1 执行环境栈(ECStack)
- 浏览器之所以能够运行JS代码:它会在计算机的内存中分配出一块区域,就是栈内存
- 作用:用来供代码执行 & 存储基本数据类型值
- 这个区域就是栈内存,ECStack,Execution Context Stack 执行环境栈
2.2 执行上下文(EC)
- 为了在执行环境栈中区分是哪个区域(全局EC(G)的代码还是函数的代码)下的代码执行,会产生一个叫执行上下文的。
- 这个区域就是全局的执行上下文,Execution Context(global)是全局执行上下文。
- 函数执行会形成全新的私有的上下文,不是全局上下文
- EC执行时,会进入ECStack,进栈执行
- 全局执行上下文中EC(G)下有window对象,指向GO
2.3 变量对象(Varibale Object)
- EC全局执行上下文中,用VO(G)全局变量对象,存储当前上下文声明的变量
2.4 声明变量的解析过程
-
执行 var 变量 = 值 分三步
- 第一步:先创建值
- 基本类型值:直接存储在栈(stack)内存中
- 引用类型值(对象和函数):开辟一个单独的内存空间,堆(Heap)
- 第二步:声明变量 declare
- 存放到当前上下文(EC)的变量对象(VO)中
- 引用类型关联,即存储的是内存地址
- 第三步:关联声明和值 defined,此操作叫定义
- 第一步:先创建值
-
只声明不定义,只执行了第二步,给默认值undefined
-
基本类型直接存在栈内存中,直接按值操作,引用数据类型是开辟单独的堆内存存储信息的,操作的是引用地址
// 从右向左
// 情况1
var a = 12;
b = 13;
// 解析过程: var a = 12; var b = 13;
// 情况2
var a = b = 13;
// 解析过程:从右向左,b = 13, var a = b;
// 情况3 成员访问优先级仅次于括号
a.x = b = 13;
b = a.x = 13;
// a.x是成员访问 在js运算优先级中,19,仅次于括号()的20
// 不管写在前面还是后边,先计算a.x = 13,再计算a.x=b
// 例子
var a = {n: 1}
var b = a;
a.x = a = {n: 2}
console.log(a.x)
console.log(b)
// a和b初始都指向{n:1}
// 先计算a.x, a.x指向{n:2}, 再计算a={n:2}
// a指向了 {n:2}
// b指向的对象被a.x变成 {n:1, x:{n:2}}
// a指向{n:2},a.x为undefined,b为{n:1, x:{n:2}}
2.5 函数的底层处理机制
var x = [12, 23];
function fn(y) {
y[0] = 100;
y = [100];
y[1] = 200;
console.log(y);
}
fn(x);
console.log(x);
// [100, 200], [100, 23]
1. JS中的上下文
- 全局上下文EC(G)
- 函数执行会形成一个全新的私有上下文
- ES6中块级私有上下文
2. 创建一个函数和创建一个变量类似
- 都是声明一个变量存储值
- 函数的函数名也算是变量 fn
- function fn(y) {...} 类似于 var fn = function(y) {...}
- 函数表达式:把一个函数作为值赋值给一个变量或者其他事物
3. 创建一个函数也需要开辟一个堆内存
- 对象的堆内存中,存储的是对象的键值对
- 函数的堆内存中,存储的是它的代码,而且是以字符串的形式存储
- 创建函数的时候就声明了函数的作用域
- scope值是当前创建函数时候所处的上下文
4. 代码的执行过程
- 执行环境栈ECStack开辟空间
- 全局上下文EC(G)中声明x以及fn,进栈,并开辟堆内存,存放数组以及函数
- 数组堆内存:[12, 23]
- 函数堆内存
- 代码字符串
- 并存储scope,EC(G)在哪个上下文中创建的,作用域是谁
- 形参y
- 函数执行,函数堆内存fn(y)形成一个全新的私有上下文AO(fn),进栈
- 形参y的值,赋值
- 作用域链,<EC(fn), EC(G)>,函数自己作用域和上级外部全局作用域
- 代码字符串执行
5. 相关概念
- 私有变量:私有上下文中声明的变量
- 形参是私有变量
- 代码执行时声明的变量 var/let/const/function
- 全局变量:全局上下文中声明的变量
- 全局变量可以通过参数传递成私有变量
- 作用域链查找机制
- 私有上下文中代码,通过作用域链去查找变量,如果没有,逐级向上
6. 函数执行的步骤
- 形成一个私有的上下文,Active Object私有变量,存储当前上下文中声明的变量,然后进栈执行
- 代码执行之前
- 初始化作用域链,scope-chain
- 结构:<(当前自己的私有上下文,函数的作用域), (上级上下文)>
- 初始化this,arguments
- 形参赋值
- 变量提升
- 初始化作用域链,scope-chain
- 代码执行
- 出栈释放
3.浏览器垃圾回收机制
- GC:浏览器的垃圾回收机制(内存释放机制)
3.1 栈内存释放
- 加载页面,会形成一个全局上下文,只有页面关闭的时候,全局上下文才会被释放。(全局变量,关闭才释放)
x = null
fn = null // 手动取消占用,变量堆内存被释放
// 代码执行完成就会出栈释放,上下文释放,占用释放
- 函数执行时会形成一个私有的上下文,进栈执行,当函数中代码执行完成,大部分情况下,形成的上下文都会被出栈释放,以此优化栈内存大小。
3.2 堆内存释放
- 方案一:chrome,查找引用
- 浏览器会在指定或者空闲时间内,查看所有的堆内存,把没有被占用的堆内存释放掉,被占用的不能释放。
- 方案二:IE,引用计数
- 创建了堆内存,如果被占用一次,则浏览器计数+1,取消占用,计数-1,当记录的数字为0时,则内存释放。
- 某些情况会导致计数混乱,会导致内存泄露现象,该释放的内存没有释放。
3.3 闭包 不被销毁的局部私有变量
- 函数执行,会形成私有上下文EC(fn)
- 函数执行之前要初始化作用域链(连接上下文) ...
- 当前上下文创建的0X001,console函数,被当前上下文以外的全局上下文f占用,当前上下文不能释放
·