JS作用域、闭包与this关键字综合实例解析

作者:纸飞机

时间:2026-10-21

浏览:397

本文通过具体代码实例,深入解析JavaScript中的作用域、闭包机制及this关键字的指向规则。详细拆解变量预解释、函数执行上下文以及全局与局部变量的交互过程,帮助开发者理解复杂场景下的变量取值逻辑。

文章目录

JavaScript作用域、闭包与this关键字综合实例解析

本文通过具体代码实例,深入解析JavaScript中的作用域、闭包机制及this关键字的指向规则。

全局变量与IIFE的执行分析


var number = 2;
var obj = {number : 5,
  fn1 : ( function() {
  this.number *= 2;
  number=number*2;
  var number=3;
    return function() {
      this.number *= 2;
      number*=3;
      alert(number);
    }
  } )()
};
var fn1 = obj.fn1;
alert(number);
fn1();
obj.fn1();
alert(window.number);
alert(obj.number);

【解析】

首先,代码中 `var fn1 = obj.fn1;` 这一行执行时,`obj.fn1` 本身是一个立即执行函数表达式(IIFE)的结果,即它已经被执行。该IIFE内部返回了一个匿名函数,但此时返回的匿名函数并未执行,只是被赋值给了 `fn1` 变量。

接着执行 `alert(number);`,此时输出的是全局变量 `number` 的值,初始为2。在赋值语句 `var fn1 = obj.fn1;` 执行过程中,触发了 `obj.fn1` 所指向的IIFE的运行。


this.number *= 2;
number=number*2;
var number=3;

这涉及以下三句代码的执行逻辑:

需要注意的是,任何直接执行的匿名函数(此处指IIFE),其内部的 `this` 关键字默认指向全局对象 `window`(在非严格模式下)。

因此,在IIFE内部执行 `this.number *= 2;` 时,实际上是将全局变量 `number` 乘以2,使其值变为4。这就是为什么随后 `alert(number);` 输出4的原因。

而在IIFE内部执行 `number = number * 2;` 时,JavaScript引擎会查找当前作用域内的变量。由于存在 `var number = 3;` 的声明提升,局部变量 `number` 被声明但未赋值(值为 `undefined`)。因此,`number = number * 2;` 实际上是 `undefined * 2`,结果为 `NaN`,并未改变全局变量,该语句对全局变量无实际影响。

随后执行 `fn1();`,这实际上是执行 `obj.fn1` 返回的那个匿名函数。

匿名函数调用中的this指向与局部变量


this.number *= 2;
number*=3;
alert(number);

此时再次进入一个匿名函数作用域,`this.number *= 2;` 使得全局变量 `number` 从4变为8。接着执行 `number *= 3;`,这里查找的是当前作用域块内的 `number`(即外层IIFE定义的局部变量,值为3),因此该局部变量变为9。最后 `alert(number);` 输出的是当前作用域内的局部变量,即9。如果执行 `alert(this.number);`,则指向全局变量,输出8。

接下来执行 `obj.fn1();`,这同样执行 `fn1` 内部返回的匿名函数。

对象方法调用对this及属性的影响


this.number *= 2;
number*=3;
alert(number);

但此时调用方式是对象方法调用,因此 `this` 指向 `obj` 对象。执行 `this.number *= 2;` 使得 `obj` 对象的 `number` 属性从5变为10。接着执行 `number *= 3;`,依然查找当前作用域块内的局部变量(之前已变为9),因此该局部变量变为27。`alert(number);` 输出作用域块内的局部变量,即27;若执行 `alert(this.number);`,则指向 `obj` 对象的 `number`,输出10。

最后执行 `alert(window.number);`,经过前面的执行过程,全局变量 `number` 在IIFE中变为4,在 `fn1()` 调用中变为8。注意 `obj.fn1();` 对全局变量没有影响,因此最终全局变量值为8。

执行 `alert(obj.number);`,只有 `obj.fn1();` 这一调用修改了 `obj` 对象的 `number` 属性,使其值为10,因此输出10。

变量声明提升与NaN的产生机制


(function(){
   var a=10;
  fn();
  function fn(){
    var a=a+10;
    console.log(a);
     return a;
  }
  console.log(a);
  console.log(fn()+10);
})();

在另一个示例中,函数 `fn` 内部的变量 `a` 先被声明但未赋值,随后进行运算。由于局部作用域内已存在同名变量 `a`,JavaScript不会向外层查找同名变量,而是使用局部变量。未初始化的局部变量 `a` 与数字进行运算,结果为 `NaN`。

语句 `console.log(fn()+10);` 的执行过程包含两个部分:首先执行 `console.log(fn());`,然后执行 `console.log(fn()+10);`。

结果如下:

NaN 10 NaN NaN

如果将题目修改为移除内部 `var a` 的声明(即不重新声明局部变量),


(function(){
  var a=10;
  fn();
  function fn(){
    a=a+10;
    console.log(a);
    return a;
  }
  console.log(a);
  console.log(fn()+10);
})();

结果将变为:

20

20

30

40

更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《JavaScript数组操作技巧总结》、《JavaScript排序算法总结》、《JavaScript遍历算法与技巧总结》、《JavaScript数学运算用法总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript查找算法技巧总结》及《JavaScript错误与调试技巧总结》

希望本文所述对大家JavaScript程序设计有所帮助。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章