Skip to main content

浏览器中JS的执行机制

变量提升

指在JavaScript代码执行过程中,JavaScript引擎把变量的声明部分函数的声明部分提升到代码开头的“行为”。变量被提升后,会给变量设置默认值 undefined

showName()
console.log(myName)
getName()
var myName = '阿斯顿'
function showName() {
console.log('showName')
}
var getName = function () {
return 'getName'
}

结果 'showName' => '阿斯顿' => throw getName is not a function

模拟变量提升

/* 变量提升 */
var myName = undefined
function showName() {
console.log('showName')
}
var getName = undefined


/* 代码执行 */
showName()
console.log(myName)
getName()
myName = '阿斯顿'
getName = function () {
return 'getName'
}

并非物理层面移动代码,而是在编译阶段被 js 引擎放入内存中

执行上下文是JavaScript执行一段代码时的运行环境

调用栈

  • 每调用一个函数,JavaScript引擎会为其创建执行上下文,并把该执行上下文压入调用栈,然后JavaScript引擎开始执行函数代码。
  • 如果在一个函数A中调用了另外一个函数B,那么JavaScript引擎会为B函数创建执行上下文,并将B函数的执行上下文压入栈顶。
  • 当前函数执行完毕后,JavaScript引擎会将该函数的执行上下文弹出栈。
  • 当分配的调用栈空间被占满时,会引发“堆栈溢出”问题。

作用域

作用域是指在程序中定义变量的区域,该位置决定了变量的生命周期。通俗地理解,作用域就是变量与函数的可访问范围,即作用域控制着变量和函数的可见性和生命周期。

全局作用域、函数作用域

ES5 之前js 只有

  • 全局作用域,在代码任何地方都能访问,生命周期伴随页面的生命周期
  • 函数作用域,在函数中定义的变量或函数,只能在函数内部访问,函数执行完后就会被销毁

块级作用域

示例

function foo(){
var a = 1
let b = 2
{
let b = 3
var c = 4
let d = 5
console.log(a)
console.log(b)
}
console.log(b)
console.log(c)
console.log(d)
}
foo()
  1. 编译并创建执行上下文

    ==================================================

    变量环境:a = undefined; c = undefined

    词法环境(栈):【b=undefined】

    ==================================================

    var 声明的会放到变量环境,let,const 声明的会放到词法环境(lexical environment)。

    词法环境维护了一个栈,进入一个作用域后,就会把变量压到栈顶,执行完后弹出。

  2. 执行代码

    执行到代码块

    ==================================================

    变量环境:a = 1; c = undefined

    词法环境(栈):【b = 2】【b = undefined; d = undefined】

    ==================================================

    执行到 console.log(a),a 先从词法环境向下找,然后在变量环境找

  3. 执行到 console.log(a)

    ==================================================

    变量环境:a = 1; c = 4

    词法环境(栈):【b = 2】【b = 3; d = 5】

    ==================================================

    执行到 console.log(a),a 先从词法环境向下找,然后在变量环境找

  4. 块级执行完

    ==================================================

    变量环境:a = 1; c = 4

    词法环境(栈):【b = 2】

    ==================================================

    词法环境弹出。后面继续执行。。。

作用域链与闭包

作用域链

作用域链是由词法作用域决定的,而词法作用域是由代码结构来确定的。

词法作用域

词法作用域就是指作用域是由代码中函数声明的位置来决定的,所以词法作用域是静态的作用域,通过它就能够预测代码在执行过程中如何查找标识符。

词法作用域是代码编译阶段就决定好的,和函数是怎么调用的没有关系

块级作用域的变量查找

function bar() {
var myName = "极客世界"
let test1 = 100
if (1) {
let myName = "Chrome浏览器"
console.log(test)
}
}
function foo() {
var myName = "极客邦"
let test = 2
{
let test = 3
bar()
}
}
var myName = "极客时间"
let myAge = 10
let test = 1
foo()

1 - 5 表示查找顺序

闭包

function foo() {
var myName = "极客时间"
let test1 = 1
const test2 = 2
var innerBar = {
getName:function(){
console.log(test1)
return myName
},
setName:function(newName){
myName = newName
}
}
return innerBar
}
var bar = foo()
bar.setName("极客邦")
bar.getName()
console.log(bar.getName())

this

  1. 当函数作为对象方法调用的时候,this 指向该对象
  2. 当函数正常调用时,this 指向全局对象 window ,严格模式是 undefined
  3. 嵌套函数中的 this 不会继承外层函数的 this