javascript,普通函数的 this和箭头函数的 this对比

箭头函数和普通函数最大的区别之一是:
 
  • 普通函数的 this调用时绑定(谁调用,this 就指向谁)。
  • 箭头函数的 this定义时绑定(继承自「定义箭头函数时所处的外层作用域」的 this),且箭头函数本身没有自己的 this,无法被 call/apply/bind 修改。
// 全局作用域(浏览器中 this 指向 window,Node 中指向 global)
const person = {
  name: "张三",
  sayNameNormal: function() {
    console.log(this.name); 
  },
  // 箭头函数定义在「对象字面量的属性值位置」
  sayNameArrow: () => {
    console.log(this.name); 
  }
};

这里面存在一个关键误区:很多人以为箭头函数定义在 person 对象里,外层作用域就是 person—— 但对象字面量不是独立的作用域

所以,接下来,我们就要搞清楚,什么是独立的作用域?

要搞清楚「独立作用域」的范畴,首先明确核心定义:独立作用域是能创建新的变量 / 标识符查找范围的语法结构,变量在其中声明后不会泄漏到外部,且内部能形成独立的 this 绑定(针对函数)。
 
下面先列出 JS 中所有能创建独立作用域的语法结构,再结合例子对比「有作用域」和「无作用域」的区别,帮你彻底理解。
 

一、JS 中能创建独立作用域的核心结构

 

1. 函数作用域(最基础)

 
所有普通函数(声明式、表达式、匿名函数)都会创建独立的函数作用域,箭头函数继承外层作用域,但本身不创建新作用域。
// 全局作用域
const a = 1;

function fn() {
  // 函数独立作用域
  const a = 2;
  console.log(a); // 输出 2(优先找函数内的 a)
}

fn();
console.log(a); // 输出 1(全局的 a 不受函数内影响)

2. 块级作用域(ES6+)

 
{} 配合 let/const/class/import 声明变量时,会创建块级作用域(仅 var 不遵循块级作用域)。
 
常见的块级作用域场景:
 
  • if/else 语句的 {}
  • for/while 循环的 {}
  • switch 语句的 {}
  • 直接写的独立 {}
// 全局作用域
if (true) {
  // 块级独立作用域
  let b = 3; // let 绑定块级作用域
  var c = 4; // var 不绑定块级作用域,泄漏到全局
}

console.log(b); // 报错:b is not defined(块级作用域隔离)
console.log(c); // 输出 4(var 无视块级作用域)

3. 模块作用域(ES6 模块)

 
ES6 模块(.mjs 文件或设置 type="module"<script>)会创建独立的模块作用域,模块内的变量默认不暴露到全局。
// module.js(模块作用域)
const moduleVar = "模块内变量";
export default moduleVar;

// 主文件
import moduleVar from './module.js';
console.log(moduleVar); // 输出 "模块内变量"
console.log(window.moduleVar); // undefined(模块变量不泄漏到全局)

4. 额外补充:eval 作用域(慎用)

 
eval() 执行字符串代码时,会创建临时的独立作用域(严格模式下),非严格模式则融合到当前作用域(不推荐使用)。
 

二、对比:无独立作用域的常见结构(重点区分)

 
这些结构看似有 {},但不会创建新作用域,变量 /this 都会沿用外层作用域:
 
  1. 对象字面量{ key: value }{} 仅用于定义对象属性,无作用域隔离;
  2. 对象方法的简写const obj = { fn() {} } 里的 fn 是普通函数(自身有作用域),但 obj{} 无作用域;
  3. 解构赋值的 {}const { name } = person{} 仅用于解构,无作用域;
 
典型对比例子
// 1. 对象字面量(无独立作用域)
const obj = {
  x: 10,
  // 这里的箭头函数继承外层(全局)作用域,因为 obj 的 {} 无作用域
  arrowFn: () => {
    console.log(this); // 指向全局(window/global)
  },
  // 普通函数自身有作用域,this 调用时绑定
  normalFn: function() {
    console.log(this); // 调用时指向 obj
  }
};

// 2. 独立 {} 块(有块级作用域)
{
  let x = 20; // 块级作用域内的变量
}
console.log(x); // 报错:x is not defined(块级作用域隔离)

三、关键总结:如何快速判断是否有独立作用域?

 
一个简单的判断方法:
 
  • 看「变量声明」:如果在某个 {} 内用 let/const 声明的变量,外部无法访问 → 有独立作用域;
  • 看「this 绑定」:如果是函数 / 模块 → 能形成独立的 this 绑定(箭头函数除外);如果是对象字面量 → 无独立 this 绑定。
 

总结

 
  1. 有独立作用域的结构:普通函数(含函数表达式)、ES6 块级作用域(if/for/{} + let/const)、ES6 模块;
  2. 无独立作用域的常见结构:对象字面量、解构赋值的 {}、仅含 var 的空 {}
  3. 核心区别:独立作用域会隔离变量(外部无法访问内部 let/const 变量),而非独立作用域的 {} 仅作为语法结构,变量 /this 均沿用外层。

 

 

 

 
posted @ 2026-03-08 21:36  chenlight  阅读(1)  评论(0)    收藏  举报