js的作用域,作用域链,执行上下文,变量对象,活动对象
1、什么是作用域?作用域链?
作用域是个很抽象的概念,他是javaScript代码中变量和函数可访问的环境。他决定了哪些代码能访问某些变量或者属性。
作用域分为:全局作用域,函数作用域,块级作用域
作用域链决定了变量的查找顺序和查找范围。
let a='123'function inner(){console.log(a)}function outer(){let a='456'inner()}outer() //123
以上代码共有三个作用域:其中一个全局作用域,两个函数作用域。
两个函数的变量对象分别对应一条作用域链
inner变量对象-》全局变量对象
outer变量对象-》全局变量对象
所以,inner函数执行的时候,沿着作用域链找到了全局变量对象(代码执行的时候全局变量对象其实已经是活动对象了)的a变量,因此输出‘123’
2、什么是执行上下文?执行上下文栈?
执行上下文指的是一种执行环境,执行上下文栈是一种存储执行上下文的栈结构。当js脚本开始执行的时候,首先会将全局的执行上下文推入栈中,如果在全局执行上下文中调用了某个函数,则会创建一个函数执行上下文,并推入栈中,函数执行上下文执行完毕后会弹出栈,继续全局执行上下文的执行。
总之,执行上下文栈中栈顶永远是当前正在执行的上下文环境,栈底永远是全局执行上下文。
3、变量对象和活动对象是什么?
每一个执行上下文环境都会对应一个变量对象,用于存储该上下文环境中的变量和函数。比如,函数一经调用,函数的执行上下文就被推入栈中,在函数体代码正式执行之前,该执行上下文的变量对象会进行创建。
function(num1,num2){let result=num1+num2console.log(result)
}
比如这个函数,上下文对应的变量对象就有num1,num2,result,arguments这些变量,可供函数体中的代码进行访问。
活动对象是变量对象其实是一个对象,当函数体开始执行的时候,变量对象中的变量就会被初始化并赋值,这时候变量对象就变成了活动对象。
4、作用域链增强
两种方式:with语句块,catch块
with语句块:
function test(){let a='qwe'with(location){let b=href+a;}return b;}console.log(test())
如上,test函数调用的时候,首先是创建一个函数作用域和函数的执行上下文,在该上下文中声明了变量a。执行到with语句时,在作用域链的前端又新加了一个以location为变量对象的上下文。在with语句块中声明的变量b,只在新的上下文中可访问。with语句执行完毕后,b就会被销毁。因此在函数test的执行上下文中访问b会报错。
想要在函数作用域中能够访问到内部块级作用域中的变量,则变量应该用var去声明,因为var声明的变量会挂到最近的函数执行上下文,而let声明的变量只会挂到最近的块级执行上下文。如下:
function test(){let a='qwe'with(location){var b=href+a;}return b;}console.log(test())
with使访问变量更加方便,location.href可以直接写成href。但是带来了很大的性能开销,因此在严格模式下禁用。
catch块:
function createErrorLogger() {let errorCount = 0; // 外部作用域变量return function (error) {try {throw error;} catch (e) {errorCount++; // 修改外部作用域变量(通过闭包)console.log(`Error ${errorCount}:`, e.message);console.log("Accessing outer var:", errorCount); // 可访问外部变量}// console.log(e); // 仍无法在外部访问 e};
}
如上代码:catch
块通过词法环境动态绑定异常对象到标识符 e
。e
仅在 catch
块内有效,且必须显式通过 e
访问(类似函数参数的传递)。
with和catch对比:
特性 | with 语句 | catch 块 |
---|---|---|
作用域处理方式 | 动态修改作用域链(运行时调整) | 动态创建词法环境(编译时绑定) |
对象绑定方式 | 将外部对象临时插入作用域链顶部 | 将异常对象绑定到标识符 e |
属性访问 | 可省略对象名(直接访问属性) | 必须显式通过 e 访问异常对象属性 |
作用域范围 | 仅限 with 块内 | 仅限 catch 块内 |
是否创建新变量对象 | 否(仅修改作用域链) | 否(动态绑定到词法环境) |
引擎实现方式 | 运行时动态调整作用域链 | 编译时生成词法环境结构 |