JS作用域、闭包与this关键字综合实例解析
本文通过具体代码实例,深入解析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程序设计有所帮助。
JS动态构建复杂嵌套JSON对象的方法
2026-11-05 15:41:52
JS负数取余为什么是负数?详解余数与模运算区别
2026-11-05 13:34:41
JS 解压出现乱码或报错怎么解决?
2026-11-05 12:32:38
JS 中 startsWith、indexOf 与正则判断字符串前缀的对比
2026-11-04 22:19:43
JS解析Excel后怎么将数据转换为JSON格式
2026-11-04 20:58:28
