一 、 JS执行引擎
JavaScript 执行引擎是浏览器或运行环境(如 Node.js)中负责解析和执行 JavaScript 代码的核心组件。它的主要作用是将 JavaScript 代码转换为机器码并执行。
二、 JS执行过程
JS执行过程中代码要执行三个过程:词法分析、语法分析、生成代码
- 词法分析:将源代码字符串分解成一系列的标记(tokens)。这些标记是代码中的基本元素,例如
var a = 2;这行代码被分解为:var、a、=、2、; 。 - 语法分析:语法分析器接收来自词法分析器的标记流,并根据语言的语法规则构建抽象语法树(AST)。AST 是源代码的层次结构表示,它反映了代码中的语法结构。如下图:
3.生成代码:一旦AST被构建,编译过程的最后一步是代码生成。代码生成器遍历AST,并根据AST的结构生成目标代码。目标代码可以是机器代码、字节码或者另一种高级语言的代码。
三、 作用域
作用域可以分为全局作用域和局部作用域
全局作用域(Global Scope):
- 全局作用域是指在任何函数之外定义的变量,这些变量可以在代码的任何地方访问。
- 在浏览器环境中,全局作用域的全局对象是
window,在Node.js中是global。
globaVar = 'I am a global variable';
function foo(){
console.log(globaVar); // 可以访问到 global Var
}
foo();
局部作用域(Local Scope) :
- 函数作用域是指在函数内部定义的变量,这些变量只能在函数内部访问。
- 使用
var关键字声明的变量具有函数作用域。
function base(){
var localVar = 'I am a local variable';
console.log(localVar); // 可以访问到 localVar
}
base();
// console.log(localVar); // 报错,localVar 在函数外不可访问
四、var,let,const的区别
var声明的变量会存在声明提升(将变量的声明提升到当前作用域的顶部)let不会
console.log(a); // 正常输出,输出underfined
var a = 1
console.log(a); //报错ReferenceError: Cannot access 'a' before initialization
let a = 1
2.重复声明
- 可以在同一个作用域内多次声明同一个 var 变量,后面的声明会覆盖前面的声明。
- 不能在同一个作用域内多次声明同一个 let 变量。否则会语法错误(SyntaxError)。
3.块级作用域
-
var 具有全局作用域和函数作用域,如果在任何函数外声明,则它为全局变量,即使在if或者for语句中也为全局变量。
-
let+{ } 拥有块级作用域,它们只在它们被声明的代码块(如 if 语句、for 循环等)内部有效。
if(true){
var a = 1
let b = 2
}
console.log(a); //1
console.log(b); //b is not defined
for(var i = 0; i < 10 ; i ++){
console.log(i); //输出 0~9
}
console.log(i); //10
for(let i = 0; i < 10 ; i ++){
console.log(i); //输出 0~9
}
console.log(i); // i is not defined
4.const 关键字用于声明一个只读的常量,这意味着一旦声明并初始化,它的值就不能再被改变。
const a = 1
a = 2
console.log(a); //TypeError: Assignment to constant variable.
5.暂时性死区 在代码块内,使用 let 声明变量之前,该变量是不可用的。也就是说,在变量声明之前,访问这个变量会抛出 ReferenceError。暂时性死区的存在是为了保证代码的执行顺序和逻辑。
let a = 1
if (true) {
console.log(a); // 暂时性死区
let a = 2
}
五、欺骗词法作用域
1.eval
eval( )可以将任意字符串当成代码执行,如以下,将字符串'var b = 3'当成代码执行,所以得到b=3,再传入实参1给形参a,最后得到正确结果1,3。
function foo(str,a){
eval(str) // var b = 3
console.log(a,b);
}
foo('var b = 3', 1 )
2.with
with( ){ } 当对象中没有属性 x 时,使用with修改 x 属性会导致 x 泄露到全局,会在全局作用域中查找或声明 a。
var o1 = {
a:1
}
var o2 ={
b:2
}
// var a = 2
function foo(obj){
with(obj){
a=2
}
}
foo(o2)
console.log(o2); //输出{b:2}
console.log(a); //输出 2
六、总结
- js的执行引擎包括浏览器和node
- js的代码执行过程分为:词法分析、语法分析、生成代码
- js 有全局作用域和函数作用域, 作用域规则:内层作用域可以访问外层作用域,外层不能访问内层
- let 与 var
- var 声明的变量会存在声明提升(将变量的声明提升到当前作用域的顶部) let 不会
- var 可以重复声明变量,let 不行
- var 在全局声明的变量会默认添加在 window 对象上, let 不会
- const 声明的变量值无法修改
- 欺骗词法:1.eval( ) 将任意字符串当成代码执行。 2.with( ){ } 当对象中没有属性x时,with修改x属性会导致 x 泄露到全局。
- 作用域就是一个独立的地盘,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。