JavaScript 的 this 绑定规则:一次讲清楚,不再当“玄学”

79 阅读3分钟

引言

你是否曾在深夜调试时,对着一个 undefined 或指向了 window 的 this 陷入沉思?this 是 JavaScript 中最强大但也最容易让人困惑的概念之一。它不像普通变量那样遵循词法作用域,而是在函数被调用时才会被绑定。今天,我们将用清晰的图示和例子,彻底揭开它的神秘面纱。

核心思想:this 的绑定取决于“调用方式”,而非“定义位置”

deepseek_mermaid_20251020_401ca0.png

规则一:默认绑定

场景:独立函数调用。

规则:在非严格模式下,this 指向全局对象(浏览器中是 window);在严格模式下,this 是 undefined

例子

function foo() {
  console.log(this.abc);
}

var abc = 2; // 全局变量,相当于 window.abc = 2

foo(); // 2

严格模式下的“安全”举措

"use strict";
function foo() {
  console.log(this); // undefined
}

foo(); // TypeError: Cannot read properties of undefined (reading 'a')

规则二:隐式绑定

场景:函数被一个“上下文对象”所拥有并调用。

规则this 指向这个调用它的对象

例子

function bar() {
  console.log(this.name);
}

const obj = {
  name: 'Aurora',
  bar: bar // 函数 bar 被作为 obj 的方法
};

obj.bar(); // 'Aurora'

隐式丢失(常见的坑!)

const name = 'Global Cat';

const obj = {
  name: 'Aurora',
  bar: function() {
    console.log(this.name);
  }
};

// 把方法赋值给一个变量
const func = obj.bar;
func(); // 'Global Cat', 因为此时是默认绑定规则

规则三:显式绑定

场景:使用 callapply, 或 bind 方法直接指定 this

规则this 被强制绑定到你传入的第一个参数对象上。

例子

function introduce(greeting) {
  console.log(`${greeting}, I'm ${this.name}`);
}

const person1 = { name: 'Harper' };
const person2 = { name: 'Aurora' };

// 1. call (参数逐个传递)
introduce.call(person1, 'Hello'); // "Hello, I'm Harper"

// 2. apply (参数以数组传递)
introduce.apply(person2, ['Hi']); // "Hi, I'm Aurora"

// 3. bind (返回一个绑定了this的新函数)
const boundFunc = introduce.bind(person1, 'Hey');
boundFunc(); // "Hey, I'm Harper"

规则四:new 绑定

场景:使用 new 关键字来调用函数(构造函数)。

规则this 会绑定到新创建的那个空对象上。

例子

function Person(name) {
  // 1. 创建一个新的空对象 {},并将this指向它
  // 2. 执行函数体,为这个新对象添加属性
  this.name = name;
  // 3. 自动返回这个新对象
}

const me = new Person('Harper');
console.log(me.name); // 'Harper'

优先级与特殊规则

优先级new绑定 > 显式绑定 > 隐式绑定 > 默认绑定

箭头函数——规则的“例外”
箭头函数没有自己的 this,它内部的 this 继承自定义它时所在的外层作用域

const obj = {
  name: 'Harper',
  regularFunc: function() {
    console.log('Regular:', this.name); // 'Harper'
  },
  arrowFunc: () => {
    console.log('Arrow:', this.name); // 指向外层(可能是window),不是obj!
  }
};

obj.regularFunc();
obj.arrowFunc();

总结

绑定规则调用方式this 指向
默认绑定foo()全局对象 / undefined (严格模式)
隐式绑定obj.foo()调用它的对象 obj
显式绑定foo.call(obj)指定的对象 obj
new 绑定new Foo()新创建的对象实例
箭头函数() => {}定义时外层作用域的 this

结尾

理解 this 的关键,就是忘掉它定义在哪,转而问自己:“这个函数是如何被调用的? ” 下次再遇到 this 的困惑时,请拿出这张“寻宝图”,按照默认、隐式、显式、new 绑定的顺序逐一排查,你一定能找到答案。