作用域、变量提升、执行上下文

执行上下文

浏览器的JavaScript引擎会创造一个特殊的环境来处理这些JavaScript代码的转换和执行。

分类
  • 全局执行上下文:(仅此一个)每当 JavaScript 引擎接收到脚本文件时,它首先会创建一个默认的执行上下文。浏览器中的全局对象就是 window对象,this 指向这个全局对象
  • 函数执行上下文:(很多个)每当函数被调用时,JavaScript引擎就会在GEC内部创建另一种执行上下文。只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文
创建
  1. 创建变量对象(VO)
  • VO:是一个在执行上下文中创建的类似于对象的容器,存储执行上下文中变量和函数声明。这种将变量和函数声明存储在内存中优先于执行代码的过程被称为变量提升(后面有章节专门分析)。
  1. 创建作用域链
  • JS作用域链:JavaScript引擎一路向上遍历执行上下文直至解析处在函数内部触发的变量和函数。JS引擎会先从自己的作用域中找,如果未找到,则会一直向上查找父作用域直至GEC作用域。
  • 每一个函数执行上下文都会创建一个作用域:作用域相当于是一个空间/环境,变量和函数定义在这个空间里,并且可以通过一个叫做作用域查找的过程访问。
  • 如果函数被定义在另一个函数内部,处在内部的函数可以访问自己内部的代码以及外部函数(父函数)的代码。这种行为被称作词法作用域查找。也叫闭包。但外部函数并不能访问内部函数的代码。
  1. 设置this关键字的值
  • this关键字指的是执行上下文所属的作用域。一旦作用域链被创建,JS引擎就会初始化this关键字的值。
  • 全局上下文中的"this"值为window
  • 函数中的"this"值为定义其的对象,而不是全局对象。
执行

在执行阶段,JS引擎会再次读取执行上下文,并用变量的实际值更新VO。

执行栈又称调用栈,记录了脚本整个生命周期中生成的执行上下文。
JavaScript是单线程语言,也就是说它只能在同一时间执行一项任务。因此,其他的操作、函数和事件发生时,执行上下文也会被创建。由于单线程的特性,一个堆叠了执行上下文的栈就会被创建,称为执行栈

回收阶段

执行上下文出栈等待虚拟机回收执行上下文

变量提升

分类
  • 函数提升
  • 变量提升,var关键字声明的变量都会被提升
提升的基本原则
  • 提升只对函数声明有效,函数表达式并不能被提升
  • 变量提升也不适用于由let或者const关键字声明的变量

变量提升常见例题

  1. 重名问题
  • 函数声明式和 var 声明的变量重名,则最终值取决于var定义的变量
  • 如果是函数表达式,那么取决于早晚,谁最晚就是谁
// 函数声明式
var fn = 12
function fn() {
    console.log('林一一')
}
console.log(window.fn)
fn()
/* 输出
*  12
*  Uncaught TypeError: fn is not a function
*/
// 函数表达式
var fn = 12
var fn = function() {
    console.log('c一一')
}
console.log(window.fn)
fn()
/* 输出
*  functon() {...}
*  c一一
*/
var a=2;
function a() {
    console.log(3);
}
console.log(typeof a);
// number
  1. 带 var 和不带 var 的区别
  • 全局作用域中不带var声明变量虽然也可以但是建议带上 var声明变量,不带 var 的相当于给window对象设置一个属性罢了。
  • 私有作用域(函数作用域),带 var 的是私有变量。不带 var 的是会向上级作用域查找,如果上级作用域也没有那么就一直找到 window 为止,这个查找过程叫作用域链。
  • 全局作用域中使用 var 申明的变量会映射到 window 下成为属性。
console.log(a, b)
var a =12, b ='c一一'
function foo(){
    console.log(a, b)
    var a = b = 13 // b 未使用var关键字,相当于给window.b赋值
    console.log(a, b)
}
foo()
console.log(a, b)
// undefined undefined 变量提升
// undefined c-- a在函数作用域中被变量提升,但是b拿到的事window
// 13 13 作用域中的a是13,window.b是13
// 12 13 window.a为12,window.b是13
  1. 等号左边下的变量提升
print()
var print = function() {
    console.log('林一一')
}
print()
/*输出
    Uncaught TypeError: print is not a function var进行了变量提升,为undefined,所以报错
/
  1. 条件判断下的变量提升
  • 在当前作用域中不管条件是否成立都会进行变量提升
if(!("value" in window)){
    var value = 2019; 
}
console.log(value);
console.log('value' in window);
// undefined
// true

你可能感兴趣的:(前端)