1. JS的基本概念
浏览器的进程模型(多进程):
- JS单线程,与GUI线程互斥(计算和渲染互斥)
- 动态弱类型,运行时才确定类型,使用前无需声明类型
- 面向对象、函数式
- 解释型语言(解释一行执行一行?不是纯解释语言,有变量提升)
const a = {
name: '111'
};
const b = a;
b.name = '222';
console.log(a, b) ## 结果 { name: '222' } { name: '222' }
复杂类型用地址表示,所以修改b的name时,a的name也会变。 另外,const的复杂类型的值是可以被改变的(是因为地址没有改变),const的简单类型不行。
var提前访问不会报错,是undefined
console.log(a)
var a = 1
相当于
var a = undefined
console.log(a)
a = 1
2. JS是怎么执行的
右侧优化部分:JIT
token -> AST
重点:
在 ES6 中,词法环境和变量环境的区别在于前者用于存储函数声明和变量(
let 和 const )绑定,而后者仅用于存储变量( var )绑定
举个例子
let a = 20;
const b = 30;
var c;
function multiply(e, f) {
var g = 20;
return e * f * g;
}
c = multiply(20, 30);
执行上下文如下:
GlobalExectionContext = {
ThisBinding: <Global Object>,
LexicalEnvironment: { // 词法环境
EnvironmentRecord: {
Type: "Object",
// 标识符绑定在这里
a: < uninitialized >,
b: < uninitialized >,
multiply: < func >
}
outer: <null>
},
VariableEnvironment: { // 变量环境
EnvironmentRecord: {
Type: "Object",
// 标识符绑定在这里
c: undefined,
}
outer: <null>
}
}
FunctionExectionContext = {
ThisBinding: <Global Object>,
LexicalEnvironment: {
EnvironmentRecord: {
Type: "Declarative",
// 标识符绑定在这里
Arguments: {0: 20, 1: 30, length: 2},
},
outer: <GlobalLexicalEnvironment>
},
VariableEnvironment: {
EnvironmentRecord: {
Type: "Declarative",
// 标识符绑定在这里
g: undefined
},
outer: <GlobalLexicalEnvironment>
}
}
留意上面的代码,let和const定义的变量a和b在创建阶段没有被赋值,但var声明的变量从在创建阶段被赋值为undefined
详细讲解:理解 JavaScript 的执行上下文这篇就够了! - 掘金 (juejin.cn)
作用域链
obj存的是内存地址
3. JS的进阶知识点
闭包
showName返回的时候生成一个闭包,闭包指向的堆空间包含返回的函数里用到的变量,并赋值给getName,一直到getName生命周期结束,闭包一直存在,即使showName已经执行结束。
缺点:内存不容易被回收,容易造成内存泄漏
apply, bind, call 可以改变this指向
const obj = {
name: '111'
show() {
console.log(this.name)
}
}
const obj1 = {
name: '222'
}
obj.show.apply(obj1) // call bind 输出 222
new的工作:右侧
垃圾回收(堆):
新生代空间:小的变量
老生代:大变量
Javascript的垃圾回收机制知多少? - 掘金 (juejin.cn)
老生代:标记清除、内存整理(分成一个小小的碎片进行,防止占用很长时间)
事件循环
微任务队列先于宏任务队列
js--事件循环机制 - zaisy'Blog - 博客园 (cnblogs.com)