this 的五种指向与十道真题:从入门到闭眼判断

8 阅读5分钟

一、this 本质是什么?

一句话:

this 不是在定义时决定的,而是在“调用时”决定的。

记住这句话非常关键。

二、this 的 5 种指向规则

1. 默认绑定(Default Binding)

函数独立调用时this 指向全局对象(浏览器 window,Node.js global
⚠️ 严格模式('use strict')下为 undefined

function test() {
  console.log(this);
}
test(); // window / undefined(严格模式)

// 函数嵌套独立调用
function outer() {
  function inner() {
    console.log(this); // window(非严格)
  }
  inner();
}

浏览器下:

window

严格模式:

undefined

2. 隐式绑定(Implicit Binding)

函数作为对象的方法调用this 指向调用该方法的对象

//隐式绑定
const obj = {
  name: 'obj',
  fn() {
    console.log(this.name);
  }
};
obj.fn(); // obj(调用者是 obj)

// 链式调用
const obj2 = { name: 'obj2', child: obj };
obj2.child.fn(); // obj(只看直接调用者 child)

this 指向:

obj

规则:

谁调用,this 指向谁

3. 隐式丢失

const obj = {
  name: "Jake",
  test() {
    console.log(this);
  }
};

const fn = obj.test;
fn();

输出:

原因:

函数已经脱离 obj 调用。

4. 显式绑定(Explicit Binding)

强制指定 this,通过 call / apply / bind

function say() {
  console.log(this.name);
}
const user = { name: 'Alice' };

say.call(user);   // Alice
say.apply(user);  // Alice

const bound = say.bind(user);
bound();          // Alice

区别

  • call / apply:立即执行,参数格式不同
  • bind:返回新函数,永久绑定,不立即执行
方法立即执行返回值
call函数结果
apply函数结果
bind新函数

5. new 绑定(new Binding)

用 new 调用函数(构造函数)this 指向新创建的空对象

function Person(name) {
  this.name = name;
}
const p = new Person('Tom');
console.log(p.name); // Tom

等价于:

const obj = {};           // 1. 创建空对象
obj.__proto__ = Person.prototype; // 2. 链接原型
Person.call(obj, 'Tom');  // 3. this 绑定到 obj
return obj;               // 4. 返回对象

this 指向:

新创建的对象

new 做了 4 件事:

  • 创建空对象
  • this 指向这个对象
  • 执行构造函数
  • 返回对象

6. 箭头函数绑定(Arrow Function Binding)

箭头函数没有自己的 this,它使用定义时外层作用域的 this,且绑定后无法修改call / apply / bind 无效)

例如

const obj = {
  name: "Jake",
  test() {
    const fn = () => {
      console.log(this);
    };
    fn();
  }
};

obj.test();

输出:

obj

三、this 优先级规则

优先级从高到低:

new 绑定

显式绑定(call/apply/bind)

隐式绑定

默认绑定

四、经典面试题

题 1

var name = "global";

const obj = {
  name: "Jake",
  test: function () {
    console.log(this.name);
  }
};

obj.test();

答案:

Jake

题 2

var name = "global";

const obj = {
  name: "Jake",
  test: function () {
    return function () {
      console.log(this.name);
    };
  }
};

obj.test()();

答案:

global

因为是普通函数调用。

题 3(箭头函数)

var name = "global";

const obj = {
  name: "Jake",
  test: function () {
    return () => {
      console.log(this.name);
    };
  }
};

obj.test()();

答案:

Jake

因为箭头函数继承 test 的 this。

五、万能判断口诀

判断 this 只看:

  • 函数怎么调用
  • 有没有 new
  • 有没有 call/apply/bind
  • 是不是箭头函数

不要看函数在哪定义!

六、一句话总结

this 永远由“调用方式”决定,而不是定义位置决定。

七、this进阶面试题目

🧠 题 1

      var a = 10;

      function test() {
        console.log(this.a);
      }

      const obj = {
        a: 20,
        test,
      };

      obj.test();

打印结果:

​编辑

👉 隐式绑定,谁调用指向谁。

🧠 题 2

     var a = 10;

      function test() {
        console.log(this.a);
      }

      const obj = {
        a: 20,
        test,
      };

      const fn = obj.test;
      fn();

打印结果:

10 (浏览器)
undefined(严格模式)

👉 隐式丢失。

🧠 题 3

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

foo.call(null);

打印结果

非严格模式:
window

严格模式:

null

👉 null / undefined 会被默认绑定替代(非严格)。

🧠 题 4

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

      var name = "global";

      const obj1 = { name: "obj1" };
      const obj2 = { name: "obj2" };

      foo.call(obj1);
      foo.call(obj2);

打印结果:

​编辑

🧠 题 5(bind 陷阱🔥)

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

const obj1 = { name: "obj1" };
const obj2 = { name: "obj2" };

const fn = foo.bind(obj1);
fn.call(obj2);

打印结果:

👉 bind 绑定后,call 改不了。

优先级:

new > bind > call

🧠 题 6(new + bind)

function Foo(name) {
  this.name = name;
}

const obj = { name: "obj" };

const Bar = Foo.bind(obj);

const p = new Bar("Jake");

console.log(p.name);
console.log(obj.name);

打印结果:

解说:

  • new 优先级最高
  •  this 指向新对象
  •  bind 失效

🧠 题 7(箭头函数)

var name = "global";

const obj = {
  name: "obj",
  foo: () => {
    console.log(this.name);
  }
};

obj.foo();

打印结果:

​编辑

解说:

  • 箭头函数没有自己的 this
  • 继承外层(全局)

🧠 题 8(箭头函数嵌套)

var name = "global";

const obj = {
  name: "obj",
  foo() {
    return () => {
      console.log(this.name);
    };
  }
};

obj.foo()();

打印结果:

解说:

箭头函数继承 foo 的 this。

🧠 题 9(setTimeout)

var name = "global";

const obj = {
  name: "obj",
  foo() {
    setTimeout(function () {
      console.log(this.name);
    }, 0);
  }
};

obj.foo();

答案:

解说:

setTimeout 里的普通函数默认绑定。

🧠 题 10(终极题🔥🔥🔥)

var name = "global";

const obj = {
  name: "obj",
  foo: function () {
    console.log(this.name);
    return function () {
      console.log(this.name);
    };
  }
};

obj.foo()();

答案

解说

obj.foo() → 隐式绑定 → obj
返回普通函数 → 默认绑定

切记口诀

判断 this 永远看:

  1. 是不是 new?
  2. 有没有 bind?
  3. 有没有 call/apply?
  4. 是不是对象调用?
  5. 是不是箭头函数?

优先级

new

bind

call/apply

隐式

默认

🌱 写在最后
写作这些技术文章的过程,也是我重新梳理知识体系的过程。
编程不仅是实现功能,更是一种思考方式。希望这篇文章不仅能帮你解决眼前的问题,更能激发你对[某个技术点]的更深层思考。
保持好奇,保持热爱。