JS基础:引擎,运行时,执行上下文

127 阅读4分钟

JavaScript 引擎

00.png 将.js文件内容转化为机器懂的语言。只要实现这个功能,就可以被叫做引擎。我们甚至可以自己编写。

词法分析 Parser

image.png

符合ECMA标准的JavaScript引擎: image.png

抽象语法树 AST

image.png

解释器 Interpreter

即时的,从第一行开始读,解释为ByteCode,运行。 image.png 这样的环境中会做很多重复的工作,如不断重复计算循环中的函数

编译器 Compiler

启动慢,先编译为计算机可以理解的low-level编程语言,再执行,相当于做了优化(Optimized) image.png

混合编译器

前两个各取所长,构成的Just In Time Compiler,使得运行速度加快。我们要写让机器更好预测的代码。

JavaScript 运行时

01.png

Philip Roberts:到底什么是Event Loop呢? image.png

Call Stack

栈溢出 Stack Overflow

Memory Heap

垃圾回收 Garbage Collection

内存泄漏 Memory Leaks

  1. addEventListener
  2. setInternal

执行上下文 Execution Context

每当我们调用函数,JavaScript引擎看到括号 (),都会创建一个新的执行上下文,即都会发生一个创建阶段和一个执行阶段。

  1. 创建阶段

在这个阶段中,执行上下文会分别创建变量对象,建立作用域链,以及确定this的指向。

  1. 代码执行阶段

创建完成之后,就会开始执行代码,这个时候,会完成变量赋值,函数引用,以及执行其他代码。

1.词法作用域

参考: JavaScript深入之变量对象

lexical scope => availabel data + variables where the function was defined,not where the function is called(dynamic scope => this keyword),to "fix it",use arrow function. 变量对象(variable object) ? 每一个执行上下文都会分配一个变量对象(variable object),变量对象的属性由 变量(variable) 和 函数声明(function declaration) 构成。在函数上下文情况下,参数列表(parameter list)也会被加入到变量对象(variable object)中作为属性。变量对象与当前作用域息息相关。不同作用域的变量对象互不相同,它保存了当前作用域的所有函数和变量。

全局对象

定义在顶层代码中。全局上下文中的变量对象就是全局对象。 可以看出,执行上下文栈(图右上角)的底层永远有个Global Execution Context。

image.png

Arguments对象

调用函数时,会为其创建一个Arguments对象,并自动初始化局部变量arguments,指代该Arguments对象。所有作为参数传入的值都会成为Arguments对象的数组元素。

  • ES6之后用...args 剩余形参代替可变长度实参列表,区别剩余形参和扩展操作符,它们的作用恰好相反。

变量提升 Hoisting

变量提升发生在上下文创建阶段。JavaScript引擎看到var或者function的时候,会提升他们,并在内存中分配空间。

image.png

  • 变量:提升了左边的一部分即var teddy = undefined。如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性。

  • 函数表达式

var sayhi = function() {
    console.log('hi')
}//no hoisting
sayhi();
  • 函数声明式: function关键字+命名函数的标识符+()+{}
sayhi();
function sayhi() {
    console.log('hi')
}//hoisting

2.作用域链 Scope chain

参考: JavaScript深入之作用域链一道js面试题引发的思考

查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫做作用域链。

3.this 关键字

this是动态作用域的。

this :is the object that the function is a property of. ===>>> who called me ? “点运算符左边”是谁

this 原理

由于函数是一个单独的值,所以它可以在不同的环境(上下文)执行。JavaScript 允许在函数体内部,引用当前环境的其他变量。

var f = function () {
  console.log(this.x);
}
var x = 1;
var obj = {
  f: f,
  x: 2,
};

// 单独执行
f() // 1

// obj 环境执行
obj.f() // 2

image.png image.png

this作用

  1. give methods access to their object image.png
  2. execute same code for multiple object image.png

动态和静态作用域链

image.png obj并没有调用anotherFunc,而是sing函数在内部调用了anotherFunc,也就说嵌套函数不继承词法环境意义上父函数的环境,this使用动态作用域,解决方法:

  1. 箭头函数 image.png
  2. bind image.png
  3. self = this
引申 call,apply & bind
  • 前两个用来从别的对象中“借用方法”,立即执行,两个区别在于传递参数列表的方法,call用逗号分隔,apply用数组形式传递

  • bind返回一个新的函数,使我们可以稍后调用有特定的上下文或this关键字的函数

image.png