JS作用域的“江湖”:从V8引擎到变量的隐身术(上)

209 阅读3分钟

JS作用域的“江湖”:从V8引擎到变量的隐身术(上)

前言

江湖传言,前端开发的世界里,作用域是最神秘的门派之一。你以为你掌控了变量,其实变量早已在作用域的迷雾中“隐身”了。今天,我们就来揭开 JavaScript 作用域的神秘面纱,看看 V8 引擎背后到底藏着哪些玄机。

一、什么是作用域?

作用域(Scope)就是变量的“活动范围”,决定了你在代码的哪个位置可以访问到某个变量。就像武林门派的地盘,出了地盘就不认你这号人。

  • 全局作用域 :江湖老大,谁都能见。
  • 函数作用域 :小门小派,只有本门弟子(函数内部)才能见。
  • 块级作用域 :let/const 新晋门派,只有大括号内的弟子能见。

二、变量提升的“障眼法”

你以为变量声明在后面就用不了?错!var 变量有“障眼法”——变量提升。

console.log(a); // undefined
var a = 10;

上面这段代码其实等价于:

var a;
console.log(a); // undefined
a = 10;

这就是变量提升。var 声明的变量会被提升到作用域顶部,但赋值不会提升。

let/const 的“正派作风”

let 和 const 可不是这么随便的江湖小混混,它们不会变量提升,遇到“暂时性死区”(TDZ)直接报错:

console.log(b); // 
ReferenceErrorCannot 
access 'b' before 
initialization
let b = 20;

三、作用域链:变量查找的“寻宝图”

当你在函数里访问变量时,JS 会先在当前作用域找,找不到就去上一级作用域,一直找到全局作用域为止。这条查找路径就是“作用域链”。

var x = '全局';
function foo() {
  var x = 'foo 局部';
  function bar() {
    console.log(x); // 'foo 
    局部'
  }
  bar();
}
foo();

bar 函数找不到自己的 x,就去 foo 的作用域找,找到了就不再往上找。

四、闭包:作用域的“藏宝阁”

闭包(Closure)是函数和其词法作用域的组合。它让函数即使脱离了原来的作用域,也能记住当时的变量。

function makeCounter() {
  let count = 0;
  return function() {
    count++;
    return count;
  }
}
const counter = makeCounter
();
console.log(counter()); // 1
console.log(counter()); // 2

count 变量被“锁”在闭包里,外部无法直接访问,但每次调用 counter() 都能操作它。

五、with 和 eval:江湖的“邪门歪道”

  • with :可以动态扩展作用域,但会污染全局变量,V8 早已劝退。
  • eval :能把字符串变成代码执行,强行插入当前作用域,安全隐患极大。
with(obj) {
  a = 1; // 如果 obj 没有 a,
  会在全局创建 a
}
eval('var b = 2'); // b 直接
出现在当前作用域

六、作用域的实际应用场景

  1. 模块化开发 :利用作用域隔离变量,防止命名冲突。
  2. IIFE(立即执行函数表达式) :经典的作用域隔离技巧。
(function() {
  var secret = '江湖秘籍';
  // secret 只在这里有效
})();
  1. 事件监听与闭包 :for 循环绑定事件时,闭包防止变量“串号”。
for (var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i); // 3 3 3
  }, 100);
}
// 用 IIFE 或 let 修正
for (let i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i); // 0 1 2
  }, 100);
}

七、总结

作用域是 JS 世界的根基,理解它才能写出健壮、优雅的代码。下篇我们将深入探讨作用域的奇技淫巧和“欺骗词法”的江湖传说,敬请期待!