JavaScript 核心探秘:引擎、执行过程与语言特性

171 阅读4分钟

一、JavaScript引擎

  • 一个庞大的函数,提供了执行 JavaScript 代码的环境。浏览器node都是 JavaScript 的运行时环境。

JavaScript引擎是什么:JavaScript引擎是处理js脚本的虚拟机,通常嵌入浏览器或服务器环境中,负责解析并执行代码,支持DOM操作或动态页面生成。它是一种用于将我们的代码转换成机器可读语言的引擎。
JavaScript引擎作用:将js代码编译成机器码,还负责执行代码、分配内存和垃圾回收等。
v8:当前主流的一种JavaScript引擎,是Chrome浏览器和Node.js的核心引擎。


二、v8 执行 js 代码的过程

  1. 分词/词法分析:将源代码中的字符序列转换为 token(词法单元)序列。对于 JavaScript 代码来说,词法分析器会逐字符地扫描这段代码,识别出其中的标识符、关键字、运算符、数字字面量、分隔符等不同类型的词法单元。
console.log(a);
var a = 2;
//词法单元:var、a、=、2、;
  1. 解析/语法分析:解析器会根据词法单元序列构建抽象语法树(AST)。AST 是一种树形结构,它表示了代码的语法结构。
  2. 代码生成:将 AST 转换为字节码或机器码。
  3. 执行:运行生成的机器码。代码的实际执行顺序可表示为
var a;
console.log(a);
a = 10

三、let const var 的区别

  1. let,const声明的变量不存在声明提升
console.log(name); // 输出:undefined
var name = 'xx'; // name会被提升
 
console.log(age); // 报错 ReferenceError:age没有定义
let age = 18; // age不会被提升
 
console.log(sex); // 报错 ReferenceError:sex没有定义
const sex = "女"; // sex不会被提升
  1. let,const声明的变量不能重复声明
var a = 1
var a = 2
console.log(a); // 输出:2  // var声明的 a 可重新声明 // 后面的声明会覆盖前面的声明

let b = 1
let b = 2 // 重新声明
b = 3 // 不是声明,修改 b 的值
console.log(b); // 报错 // let声明的 b 不能重新声明
  1. var声明的全局变量会被挂载在 window 上
  2. const声明的变量 值不能修改
区别点varletconst
作用域函数作用域,全局作用域块作用域块作用域
变量提升存在,变量会被初始化为 undefined不存在不存在
重复声明允许同一个作用域内重复声明,后面的声明会覆盖前面的声明不允许不允许
初始值设置可以不设置初始值可以不设置初始值必须设置初始值
能否重新赋值不能
能否改变指针指向不能

暂时性死区:在代码块内,使用letconst声明的变量在声明之前是不可用的。

let a = 1
if(true){
    console.log(a) // 报错 // 出不去 暂时性死区:let 和 const 声明的变量在声明之前是不可用的
    let a = 2;
}

四、作用域

  • 变量和函数的可访问范围,控制着变量和函数的可见性和生命周期。
  1. 全局作用域:在代码最外层或如何函数/块之外声明的变量,任何位置可访问。
  2. 函数作用域:在函数内部声明的变量,仅在该函数内访问。函数调用时会创建一个新的作用域,执行完后销毁。使用var声明的变量具有函数作用域。 函数参数也属于函数作用域。
  3. 块级作用域:由{}包裹的代码块内部的作用域。使用letconst声明的变量具有块级作用域。
if(true){ // 语句,全局
    var a = 10; // a 在全局作用域
    let b = 10; // b 在块级作用域 // let + {} 形成块级作用域 // 只有 let/const 声明的变量才会形成块级作用域
}
  • 作用域查找规则
  1. 先在当前作用域中查找,找的到就返回,找不到就去外层作用域中查找。
  2. 只能从内向外查找,不能从外向内查找。
var a=10
console.log(a); // 在全局作用域中查找a

function foo(b){
    var a = 1
    function bar(){
    console.log( a + b ); // 在 bar 函数作用域查找 a 和 b,无法找到,在外层作用域中继续查找 // 输出:3
    }
    bar()
}
foo(2)

拓展:欺骗词法

  1. with —— 当with修改对象中不存在的属性时,会导致该属性泄露到了全局。
var o={
    b:2
}
function foo(obj){
    with(obj){
        a = 2 // 没有关键字,默认为全局变量   全局中定义 a = 2
    }
}
foo(o)
console.log(a); // 输出:2
  1. eval —— 将本不属于当前作用域中的代码,强行添加到当前作用域中执行。
function foo(str){
    eval(str) // 强行将字符串转换成代码,等同于 var a = 1
    console.log(a, b) // 输出:1 2
}
var b = 2
foo('var a = 1')