导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

算法

UI、组件库

Node

业务技能

针对性攻坚

AI

公共类


函数内部 this 指向

构造函数 this 指向实例化对象

function Test() {
  //var this = {
	//	__proto__: Test.prototype
	//}
	this.name = '123';
}
var test = new Test();

AO = {
	this: window -> {
    __proto__: Test.prototype,
    name: '123'
  }
}
GO = {
	Test: f() {},
  test: {}
}

call/apply 改变 this 指向

function Person() {
	this.name = 'Lance';
	this.age = 10;
}
function Programmer() {
	Person.apply(this);
	this.work = 'Programming';
}
var p = new Programmer();
console.log(p);

Untitled

🔥 闭包、箭头函数、setTimeout 中 this

var x = {
  name: 'bw2',
  getName1: function() {
    console.log(this)
  },
  getName2: function() {
    setTimeout(() => {
      console.log(this)
    },0)
  },
  getName31: () => {
    console.log(this)
  },
  getName32: function() {
    return function() {
      console.log(this)
    }
  }
}
x.getName1();

// {name: "bw2", getName1: ƒ}
// x为调用者

x.getName2()
// {name: "bw2", getName1: ƒ}
// 箭头函数没有this,this继承外层作用域,
// x为getName2调用者,this指向x

x.getName31()
// Window {stop: ƒ, open: ƒ, alert: ƒ, confirm: ƒ, prompt: ƒ, …}
// js中作用域只有全局作用域和函数作用域
// 箭头函数this指向外层作用域window,而不是调用者x

x.getName32()()
// Window {stop: ƒ, open: ƒ, alert: ƒ, confirm: ƒ, prompt: ƒ, …}
// this的值取决于调用上下文,
// 如果一个函数不是作为某个对象的方法被调用,
// 那么this就是global object.否则就是该对象

🔥 callee/caller

arguments.callee 返回正在被执行的函数

function test(a, b, c) {
	console.log(arguments.callee.length); // === test.length = 3
	console.log(arguments.callee); // function test
}
test(1, 2, 3);

Untitled

callee 的应用 - 匿名函数递归调用

var sum = (function (n) {
  if (n <= 1) return 1;
	return n + arguments.callee(n - 1);
})(100);

console.log(sum); // 5050

Function.caller 返回调用指定函数的函数

function test1() {
	test2();
}
function test2() {
	console.log(test2.caller);
}
test1();

Untitled

🔥 函数在直接执行和被 new 执行后的 this 指向问题

var a = 5;

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

test();
new test();

GO: {
	a: 5,
	test: function test() {}
}

AO: {
  this: window => {}
	a: undefined => 0,
}
  
// 执行 test 时打印: 0, 5, 0
// 执行 new Test 时打印: 0, undefined, 0
// 最终打印顺序: 0, 5, 0, 0, undefined, 0
  
// 解析:
// 实例化 test 时,有内部 this ,但是并没有给 this 上添加 a 属性,所以 this.a 打印 undefined

Untitled


总结

✅ 一、this 的本质

this 不是在函数定义时决定的,而是在函数被「调用」时动态绑定的。

它永远指向 当前函数执行上下文中的「调用者对象」(或全局对象/undefined,取决于模式)。


✅ 二、5 种核心情况 + 1 个特例(全覆盖)

1️⃣ 默认绑定(独立函数调用)

function foo() {
  console.log(this); // 非严格模式:window;严格模式:undefined
}
foo(); // 直接调用

2️⃣ 隐式绑定(对象方法调用)

const obj = {
  name: 'Alice',
  greet() {
    console.log(this.name); // 'Alice'
  }
};
obj.greet(); // 调用时前面有 obj.

3️⃣ 显式绑定(call / apply / bind)

function greet() { console.log(this.name); }
const person = { name: 'Bob' };

greet.call(person);   // 'Bob'
greet.apply(person);  // 'Bob'
const bound = greet.bind(person);
bound();              // 'Bob'

4️⃣ new 绑定(构造函数调用)

function Person(name) {
  this.name = name; // this 指向新创建的实例
}
const p = new Person('Charlie');
console.log(p.name); // 'Charlie'

5️⃣ 箭头函数(无自己的 this)

const obj = {
  name: 'David',
  greet: () => {
    console.log(this.name); // undefined(this 来自外层作用域)
  },
  normal() {
    const arrow = () => console.log(this.name);
    arrow(); // 'David'(继承 normal 的 this)
  }
};
obj.greet(); // this 是全局(因为箭头函数定义在全局)
obj.normal(); // 'David'

🆕 特例:DOM 事件回调中的 this

button.addEventListener('click', function() {
  console.log(this); // button 元素(隐式绑定:浏览器自动 call(this=element))
});

// 箭头函数则不同:
button.addEventListener('click', () => {
  console.log(this); // 全局对象(因为箭头函数继承外层 this)
});

🏆 三、金标准:4 步判断法(万能流程)

遇到任何函数调用,按顺序问自己这 4 个问题:

🔹 第 1 步:是不是 new 调用?

🔹 第 2 步:是不是用 call / apply / bind 调用?

🔹 第 3 步:是不是通过对象属性调用?(即 obj.fn() 形式)

🔹 第 4 步:是不是箭头函数?


💡 四、常见陷阱 & 最佳实践