执行环境与作用域
1.预解析的过程中主要包含的操作内容
- 声明变量,声明函数表达式,默认赋值为undefined,js会首先把这些东西预先存储在内存中的某个地方。
- 对this赋值,无论在任何情况,this都是有值的
- 对函数声明赋值,预解析阶段对于函数申明是直接赋值,函数中的参数也会被赋值
声明变量
console.log(a); //undefined var a='222';
函数表达式
console.log(fn1); //undefined
var fn1=function(){}
函数声明
console.log(fn2); //ƒ fn2(){}
function fn2(){};
console.log(fn2) //ƒ fn2(){}
console.log(this) //Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
以上3种预解析要做的操作,都会生成执行环境,这里默认是全局的执行环境,在函数体内部还有函数体内部的准备工作。
2.函数被声明到被执行之前,内部与解析的过程
- 先对arguments变量集合和函数的具体参数进行赋值
- 假如这个函数引入了外部的一个变量,这个变量也会被赋值,这个外部变量一般称为自由变量,是通过作用域链来取得。
- 如果在函数体内部定义了一个变量或者函数表达式,这个新的变量和函数表达式也会先被赋值为undefined,如果定义了一个新的函数生命,这个函数声明也会被直接赋值,这种函数体内部定义新的变量,函数表达式,函数声明的预解析过程与全局预解析过程类似
- 另外this在函数定义的时候不会被赋值,因为this的取值是在函数被调用的时候根据调用对象的不同才能确定的。
函数被调用一次,由于纯涤的参数不同,就会产生一次不同的执行环境,因此函数的执行环境是动态的。
3.作用域
定义: 访问变量的集合
分类:全局作用域,局部作用域。
全局作用域的特点:
- 只要变量在函数外定义,这个变量就是全局变量
- 全局变量存在于全局作用域中,全局作用域专门用来提供全局变量的存储和访问
- 全局作用域中的全局变量,在整个js脚本中都可以访问
- 全局变量在全局作用域被关闭时,也就是页面关闭后被销毁。
局部作用域的特点:
- 在函数中才可以创建局部作用域,花括号不能创建独立的作用域(js中没有块级作用域的概念)
- 我们在函数内体声明的变量就是这个函数的局部变量,这个函数就是一个局部作用域。
- 局部作用域存在一种上下级关系,局部作用域除了提供当前局部作用域的变量的存储和访问,还能提供上一级作用域中变量的访问。
- 局部作用域中上下级关系是有这个函数是在哪一级作用域下创建来决定的。
- 局部作用域下面的变量名是可以重复的,在各自作用域下,用各自的同名局部变量
- 作用域最大的用处就是隔离变量,每个函数中都有自己独立的变量,同时也可以使用上一级的变量,这里需要作用域链的概念
4.作用域链
定义:函数在以爱是创建之初,局部作用域就已经确认,在不同的作用域中访问某个变量的时候,通常会有一个取值的过程
特点:
- 一般情况,局部作用域中的变量取值会先在创建这个变量的函数局部作用域中来取值。
- 如果在当前函数局部作用域中没有找到对应的变量值,就会向上一级的局部作用域中查找。
- 如果上级局部作用域中没有对应的变量,就会上更上一层的局部作用域查找,直到查找到全局作用域下,如果存在就拿来使用,如果没有找到,则报错。
var a='100'; function fn1(){ var a='200'; fn2(); } function fn2(){ console.log(a) //100 } fn1() 注:作用域链的上下级关系是在函数一开始创建的时候就决定了。
5.执行环境和作用域的关系
- 某个函数的执行环境是在函数被调用的时候才创建。某个函数只要创建了,就等于创建了一个局部作用域。
- 对于一个函数而言,它创建的局部作用域可能存在多个执行环境。
- 当这个函数没有被调用,这个函数形成的局部作用域就不会有执行环境。
- 当函数执行完毕之后,这个调用函数的执行环境就被销毁了。
- 一个函数的作用域中有多个执行环境,就是闭包的概念
function fn1(a){ var b=200; return function(){ console.log(a+b) } } var f1=fn1(100); //不会被销毁 var f2=fn1(200); //不会被销毁 f1(); //300 f2(); //400