JS核心知识点梳理上下文作用域闭包this上

8次阅读

共计 2085 个字符,预计需要花费 6 分钟才能阅读完成。

引言

满满的干货,面试必 bei 系列,参考大量资料,并集合自己的理解以及相关的面试题,对 JS 核心知识点中的作用域、闭包、this、上下文进行了梳理。由于篇幅有限,这里只对我认为最重要的知识做了介绍, 一些常识性的东西大家可以参考高程。

上下文(execution context)

又叫执行环境,环境。

执行环境定义了变量或者环境有权访问的其他数据,据定了它们的各自行为 – 高程

一个函数执行的时候,会产生一个属于自己的执行环境。环境里面有一个变量对象 variable object(VO),OA 里面存放着环境中定义的所有变量和函数, 作用域链(scope chain),this。
函数执行,环境产生被推入环境栈,函数执行完,环境出栈并被销毁(闭包例外),把控制权返回给之前的执行环境。

作用域

js 中的作用域是静态作用域,静态作用域又叫做词法作用域,采用词法作用域的变量叫词法变量。词法变量有一个在编译时静态确定的作用域。词法变量的作用域可以是一个函数或一段代码,该变量在这段代码区域内可见(visibility);在这段区域以外该变量不可见(或无法访问)。词法作用域里,取变量的值时,会检查函数定义时的文本环境,捕捉函数定义时对该变量的绑定。–wiki
作用域是一套 规则, 用于确定在何处以及如何查找变量(标识符)。– 你不知道的 javascript

作用域就是执行的时候,给环境变量赋值的一种规则,这种规则在函数定义的时候就已经确定了,和运行无关
js 只有全局作用域和函数作用域,没有块作用域。

变量提升

我们把定一个变量的行为分为两个过程,声明和定义

var a = 1
// 实际执行的是下面两步
var a 
a = 1

var 的变量声明会提升,没有 var 就是全局变量,let 没,const 有变量提升
var 的函数声明和赋值都提升

a //undefined 因为 a 的声明已经提升到最上面了
var a = 1

f() //alert 1
function f () {alert (1)
}

有几个特殊的地方虽然平时不会这么写,但是面试题会遇到:

  • 函数体中,return 后面的代码不进行变量提升,但是 return 下面的代码要进行变量提升
  • 不管条件是否成立,都要进行变量提升;
  • 匿名函数不进行 变量提升;
  • 如果变量名字发生重复,那么不再重复声明,但是要重新定义;

执行环境和作用域的关系

很多人都分不清楚执行环境和作用域的关系。其实很简单,作用域和上下文完全是两个不相干的东西。
作用域是一种规格,声明函数的时候就已经确定了。
执行环境是函数执行的时候产生的,函数在执行环境中执行。大家看下面例子

alert(a) //a is not defined

执行的时候 VO 里面没有 a,因为根据 VO 作用域链【windows】,按照规则找不到 a。

var a  = 1
alert(a)  // alert 1

执行的时候,根据规则,从 VO 作用域链【windows】头部 window 作用域开始找 a, 找到 a 了,a 为 1,则 vo 中 a 设置为 1,所以 alert 1

var a  = 1
function foo() {
    var a = 100 
    alert(a) 
}
foo() //  alert 100

执行的时候,根据规则,从 VO 作用域链【windows-foo】头部 foo 作用域开始找 a, 找到 a 了,a 为 100,则 vo 中 a 设置为 100,所以 alert 100

var a  = 1
function foo() {alert(a) 
}
foo() //  alert 100

执行的时候,根据规则,从 VO 作用域链【windows-foo】头部 foo 作用域开始找, 没找到 a。根据规则,沿上层作用域(也就是 window)开始找,找到 a 了,aw 为 1。则 vo 中 a 设置为 1,所以 alert 1

函数执行的完整过程

  1. 开辟一片栈空间,根据作用域生成上下文
  2. 形参赋值
  3. 变量提升
  4. 代码从上到下运行
  5. 执行完毕后,判断有没有闭包,没有的话上下文销毁

练习题

1. 函数传参本质
解析可参考:https://segmentfault.com/a/11…

 var ary = [1,2,3,4];
    function sum(ary) {// 私有的;ary[0] =100;
        ary = [];// 在 JS 中,遇到 {}、[] 都会开辟一个新的空间地址
        ary[0] = 10;
        console.log(ary)
    }
    sum(ary); // [10]
    console.log(ary);// [100,2,3,4]

2. 特殊变量提升

var foo=1; 
function bar(){if(!foo){var foo=10;}
    console.log(foo); 
}
bar(); //10

3. 作用域、变量提升

console.log(a); 
var a=12; 
function fn(){console.log(a); // 注意这里的 a 在本执行环境获取不到,根据作用域链搜索全局执行环境的 a
    a=13;   // 同理修改的也是全局执行环境的 a
}
fn();   
console.log(a);     
// undefined 12 13
console.log(a); 
var a=12; 
function fn(){console.log(a); 
    var a=13;   
}
fn();   
console.log(a);     
// undefined undefined 12

正文完
 0