前言:
代码执行之前的编译过程: 1、分词/词法分析 将代码分为词法单元,如var a = 2 分为 var 2 = 2 2、解析/语法分析 将词法单元组转为程序语法结构树简称AST 3、代码生成 将AST转为可执行的代码
查找变量有两种概念,lhs和rhs,lhs是赋值操作的左侧变量进行查询,找到变量进行赋值,而右侧的变量则是查找变量的值给左侧赋值(类似引用,值传递)
作用域
是什么???
作用域决定了变量和函数的使用范围,即决定可以在哪里访问变量和函数
代码被定义的时候产生,决定了变量或函数的使用范围,可以通过作用域来编译声明语句判断变量重复声明,编译赋值语句查找是否存在该变量。给变量和函数一个独立的空间,可以互不干扰,不会造成空间污染
作用域是怎么工作的呢?
-
作用域在编译过程中,如编译var a 时,编译器会询问作用域中是否存在a,如果存在那么会忽略此次声明,也就是在声明变量时,通过作用域可知道是否已经存在相同的变量,从而是否去声明该变量
-
生成运行时的代码时,代码会处理赋值操作,即a = 2或者b = a,就可以进行lhs或rhs查询作用域中是否存在变量a,存在则进行赋值操作
作用域链
何时创建??
在js引擎 完成 初始化执行上下文环境(完成初始化执行上下文环境是什么时候),就已经确定
如何工作??
嵌套的函数查找属性和对象的时候,是在当前作用域下查找,找不到就找外层作用域,直到全局作用域,由这些作用域形成了作用域链
变量提升和函数提升
js引擎执行代码时候,会先解析语法,进行编译,再去执行,因此在编译的时候会先获取所有声明的变量和函数,这个就叫变量提升和函数提升
- 变量声明,打印输出是undefined
- 函数声明,打印输出是这个函数
- 注意:
- 函数提升优先级大于变量提升优先级
- 函数声明和函数表达式是不一样
如:function a() = {},是函数声明 var a = function(){},是函数表达式
预编译四个过程,记住,变量声明的时候,变量值是undefined,也就是变量未赋值,函数声明的时候,如果遇到函数名和变量名相同,那么函数声明会覆盖变量声明 即 console.log(a) var a = 1 function a(){} 因为变量提升和函数提升 ,那么会先打印出function a(){},而不是undefined
执行上下文
类型:
- 初始化执行上下文
- 运行执行上下文
- 结束执行上下文 在执行代码的时候产生,执行函数之前会先进行准备工作,就是创建执行上下文,又称为执行环境
包括:(es5-)
- 变量对象
- 作用域链
- this
包括:(es5+)
-
词法环境:
- 环境记录: 保存着代码块内的声明的变量和函数,(相对应变量对象或者活动对象)
- 对外部词法环境的引用(outer):
从而形成了多个词法环境的嵌套结构,来实现可以访问外部环境变量的能力(相对应作用域链)
-
环境记录:
- 声明式环境记录: 声明环境: 绑定变量声明,如var、let、const、class、module、import、function 函数环境: 每个函数作用域和下文环境的具体情况 模块环境: 表示模块的外部范围以及绑定情况
- 对象式环境记录: 对象的增删改查
- 全局环境记录: 表示最外层作用域
this的指向
是执行上下文的属性,由函数执行的时候确定,函数被调用时绑定
- 函数中有this,但是没有被调用,即this前没有点,那么this就是window,严格模式是undefined
- 函数中有this,this前有点,this被调用,那么点前面是谁,this就是谁
- 点前面还有点,那么this也只是指向离this最近的点的主体,
- 在构造函数中被调用,那么this指向构造函数的实例
- 箭头函数的this继承上一级函数执行上下文的this
- 回调函数的this指向window
- call、apply、bind改变this的指向
-
默认绑定
独立函数调用
var name = '小猪课堂';
function foo(){
console.log(this) // Window{}
console.log(this.name) // 小猪课堂
}
foo();
- 隐式绑定
例如:
function foo(name) {
this.name = name;
}
let obj1 = {
foo: foo
}
obj1.foo('小猪课堂'); //foo是在obj1对象中调用,foo调用时,他的执行上下文是obj1,所以this会绑定到obj1中
- 显式绑定
call、apply、bind改变this的指向
- new绑定
- 创建一个新对象
- 新对象继承构造函数的原型
- 新对象通过apply,调用构造函数,绑定到函数调用的this(不懂这句话),this指向新对象,并且新对象调用构造函数,(使得新对象获取构造函数的属性?)怎么获取构造函数的属性
- 返回对象
闭包
上级作用域变量的生命周期因为下级作用域的引用而没有被释放,需要等到下级作用域执行完后才能得到正常释放