JavaScript 执行

JavaScript 执行

一段 JavaScript 经过编译会生成两部分:执行上下文,可执行代码。
在执行上下文中存在一个变量环境对象(Viriable Environment),保存了变量提升的内容。

简单的变量环境对象

VariableEnvironment:
     myname -> undefined, 
     showName ->function : {console.log(myname)

JavaScript 代码先编译在执行

showName()
console.log(myname)
var myname = 'hello'
function showName() {
    console.log('函数showName被执行');
}
  1. JS 引擎在环境对象中创建一个名为myname属性,并用 undefined 对其初始;
  2. JS 引擎发现同 function 定义的函数,把函数定义存储在堆(HEAP)中,并在环境对象中创建一个 showName 的属性,然后将地址指向堆中的环境位置;
  3. JS 引擎会把声明外的代码编译为字节码

调用栈 call statck

调用栈是用来管理函数调用关系的一种数据结构
把这种用来管理执行上下文的栈成为执行上下文栈,又称调用栈
console.track() 查看调用栈

let 和 const

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

  • 全局作用域中的对象在代码中的任何地方都能访问,其生命周期伴随着页面的生命周期
  • 函数作用域就是在函数内部定义的变量或者函数,并且定义的变量或者函数只能在函数内部被访问。函数执行结束之后,函数内部定义的变量会被销毁
    代码块内部定义的变量外部是访问不到的,代码块中的代码执行完成,代码块中定义的变量就会销毁。

S6 之前是不支持块级作用域的,因为当初设计这门语言的时候,并没有想到 JavaScript 会火起来,所以只是按照最简单的方式来设计。没有了块级作用域,再把作用域内部的变量统一提升无疑是最快速、最简单的设计,不过这也直接导致了函数中的变量无论是在哪里声明的,在编译阶段都会被提取到执行上下文的变量环境中,所以这些变量在整个函数体内部的任何地方都是能被访问的,这也就是 JavaScript 中的变量提升。

ES6 是如何做到既要支持变量提升的特性,又要支持块级作用域的呢?”

  • 第一步是编译并创建执行上下文,下面是我画出来的执行上下文示意图,你可以参考下:
  • 函数内部通过 var 声明的变量,在编译阶段全都被存放到变量环境里面了。
  • 通过 let 声明的变量,在编译阶段会被存放到词法环境(Lexical Environment)中
  • 在函数的作用域内部,通过 let 声明的变量并没有被存放到词法环境中。

作用域链

每个执行上下文的变量环境中,都包含一个外部引用,
用来指向外部的执行上下文,我们把这个外部引用成为outer.

词法作用域
词法作用域是指作用域是有代码中函数声明的
法作用域是代码阶段就决定好的,和函数是怎么调用的没有关系
词法作用域
词法作用域是指作用域是由代码中函数声明的位置来决定的,所以词法作用域是静态作用域。词法作用域是代码阶段就确定好的,和函数执行无关。

闭包


function foo() {
    var myName = "li"
    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("liyunfei")
bar.getName()
console.log(bar.getName())

当执行到foo函数时的调用栈情况

foo函数执行上下文 =》变量环境, 词法环境

全局执行上下文 =》变量环境, 词法环境

闭包是怎么回收的

this

执行上下文:
变量环境、词法环境、outer、this;

你可能感兴趣的:(JavaScript 执行)