一、JavaScript引擎
- 一个庞大的函数,提供了执行 JavaScript 代码的环境。浏览器和node都是 JavaScript 的运行时环境。
JavaScript引擎是什么:JavaScript引擎是处理js脚本的虚拟机,通常嵌入浏览器或服务器环境中,负责解析并执行代码,支持DOM操作或动态页面生成。它是一种用于将我们的代码转换成机器可读语言的引擎。
JavaScript引擎作用:将js代码编译成机器码,还负责执行代码、分配内存和垃圾回收等。
v8:当前主流的一种JavaScript引擎,是Chrome浏览器和Node.js的核心引擎。
二、v8 执行 js 代码的过程
- 分词/词法分析:将源代码中的字符序列转换为 token(词法单元)序列。对于 JavaScript 代码来说,词法分析器会逐字符地扫描这段代码,识别出其中的标识符、关键字、运算符、数字字面量、分隔符等不同类型的词法单元。
console.log(a);
var a = 2;
//词法单元:var、a、=、2、;
- 解析/语法分析:解析器会根据词法单元序列构建抽象语法树(AST)。AST 是一种树形结构,它表示了代码的语法结构。
- 代码生成:将 AST 转换为字节码或机器码。
- 执行:运行生成的机器码。代码的实际执行顺序可表示为
var a;
console.log(a);
a = 10;
三、let const var 的区别
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不会被提升
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 不能重新声明
var声明的全局变量会被挂载在 window 上const声明的变量 值不能修改
| 区别点 | var | let | const |
|---|---|---|---|
| 作用域 | 函数作用域,全局作用域 | 块作用域 | 块作用域 |
| 变量提升 | 存在,变量会被初始化为 undefined | 不存在 | 不存在 |
| 重复声明 | 允许在同一个作用域内重复声明,后面的声明会覆盖前面的声明 | 不允许 | 不允许 |
| 初始值设置 | 可以不设置初始值 | 可以不设置初始值 | 必须设置初始值 |
| 能否重新赋值 | 能 | 能 | 不能 |
| 能否改变指针指向 | 能 | 能 | 不能 |
暂时性死区:在代码块内,使用let和const声明的变量在声明之前是不可用的。
let a = 1
if(true){
console.log(a) // 报错 // 出不去 暂时性死区:let 和 const 声明的变量在声明之前是不可用的
let a = 2;
}
四、作用域
- 变量和函数的可访问范围,控制着变量和函数的可见性和生命周期。
- 全局作用域:在代码最外层或如何函数/块之外声明的变量,任何位置可访问。
- 函数作用域:在函数内部声明的变量,仅在该函数内访问。函数调用时会创建一个新的作用域,执行完后销毁。使用
var声明的变量具有函数作用域。 函数参数也属于函数作用域。 - 块级作用域:由
{}包裹的代码块内部的作用域。使用let或const声明的变量具有块级作用域。
if(true){ // 语句,全局
var a = 10; // a 在全局作用域
let b = 10; // b 在块级作用域 // let + {} 形成块级作用域 // 只有 let/const 声明的变量才会形成块级作用域
}
- 作用域查找规则
- 先在当前作用域中查找,找的到就返回,找不到就去外层作用域中查找。
- 只能从内向外查找,不能从外向内查找。
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)
拓展:欺骗词法
with—— 当with修改对象中不存在的属性时,会导致该属性泄露到了全局。
var o={
b:2
}
function foo(obj){
with(obj){
a = 2 // 没有关键字,默认为全局变量 全局中定义 a = 2
}
}
foo(o)
console.log(a); // 输出:2
eval—— 将本不属于当前作用域中的代码,强行添加到当前作用域中执行。
function foo(str){
eval(str) // 强行将字符串转换成代码,等同于 var a = 1
console.log(a, b) // 输出:1 2
}
var b = 2
foo('var a = 1')