js的this绑定函数call,bind,apply
在JavaScript的世界里,this无疑是最让开发者又爱又恨的关键词之一。初学时觉得它简单易懂,深入后才发现其中暗藏玄机。本文将系统梳理this的作用及其在不同场景下的指向,帮助你理清思路,避免常见误区。
this的作用:动态上下文的指针
this,虽然字面意思是"这个",但在JS中,它的真正作用是作为函数运行时的上下文指针。它决定了当前代码块中引用的对象是谁。理解this的本质,就是理解JS函数执行时的环境。
举个例子:
const obj = {
name: '小明',
sayHi() {
console.log(this.name);
}
};
obj.sayHi(); // 输出:小明
这里的this指向obj对象本身。看似简单,但实际开发中,this的指向常常因为调用方式不同而发生变化。
this的指向全景梳理
JavaScript中,this的指向并非一成不变,而是取决于函数的调用方式。下面系统梳理常见的this指向场景:
1. 全局环境下的this
在浏览器环境中,最外层的this默认指向window对象。
console.log(this === window); // true
在Node.js环境下,顶层的this是{}(即module.exports),而不是global。
2. 作为对象方法调用
当函数作为对象的方法被调用时,this指向该对象。
const obj = {
name: '小明',
sayHi() {
console.log(this.name);
}
};
obj.sayHi(); // 输出:小明
3. 构造函数中的this
使用new关键字调用构造函数时,this指向新创建的对象。
function Person(name) {
this.name = name;
}
const p = new Person('小红');
console.log(p.name); // 小红
4. 箭头函数的this
箭头函数的this由其定义时的外层作用域决定,而不是调用时。它不会被任何方式改变。
const obj = {
name: '小明',
sayHi: () => {
console.log(this.name); // undefined
}
};
obj.sayHi();
5. 事件处理器中的this
在DOM事件处理函数中,this指向触发事件的DOM元素。
document.getElementById('btn').onclick = function() {
console.log(this); // <button id="btn">
};
6. 定时器、回调函数中的this
setTimeout、setInterval中的普通函数,this在非严格模式下指向window,严格模式下为undefined。
setTimeout(function() {
console.log(this); // window 或 undefined
}, 1000);
7. call、apply、bind显式绑定
通过call、apply、bind可以显式指定this的指向。
function show() {
console.log(this.name);
}
const obj = { name: '小明' };
show.call(obj); // 小明
show.apply(obj); // 小明
const boundShow = show.bind(obj);
boundShow(); // 小明
8. 类方法与原型链上的this
类方法中的this默认指向实例对象。原型链上的方法同理,this指向调用该方法的对象。
class Cat {
constructor(name) {
this.name = name;
}
meow() {
console.log(this.name + ' 喵喵喵');
}
}
const c = new Cat('咪咪');
c.meow(); // 咪咪 喵喵喵
9. 立即执行函数(IIFE)中的this
非严格模式下,IIFE中的this指向window;严格模式下为undefined。
(function() {
'use strict';
console.log(this); // undefined
})();
10. 严格模式下的this
严格模式下,单独调用函数时this为undefined,不会自动指向window。
'use strict';
function test() {
console.log(this); // undefined
}
test();
11. 数组方法、forEach等回调里的this
部分数组方法(如forEach)允许手动传递this。
const obj = { name: '小明' };
[1, 2, 3].forEach(function() {
console.log(this.name);
}, obj); // 小明 小明 小明
总结:
JavaScript中的this,本质上是函数运行时的上下文指针。其指向完全取决于函数的调用方式,而非定义方式。只有深入理解这些规则,才能在实际开发中游刃有余,避免常见的陷阱和误区。
call、apply、bind:this绑定三兄弟,谁才是你的菜?
说到this绑定,call、apply、bind绝对是前端开发者的"老熟人"。它们就像三兄弟,长得像、性格却各有千秋。下面咱们一一盘点,看看谁才是你的"真命天子"。
1. call:显式绑定this,参数挨个传
用法简介:
call方法可以让你"临时借用"别的对象来当作函数的this,并且参数要一个个写。
function sayHello(age, city) {
console.log(`我是${this.name},今年${age}岁,来自${city}`);
}
const obj = { name: '小明' };
sayHello.call(obj, 18, '北京'); // 我是小明,今年18岁,来自北京
推荐场景:
- 想让一个函数在不同对象上下文中执行。
- 需要灵活传递参数。
注意事项:
- 非严格模式下,this为null/undefined会自动指向window。
- call不能链式继承class。
2. apply:参数打包成数组,适合批量传参
用法简介:
apply和call几乎一模一样,唯一的区别就是参数要用数组打包。
function sum(a, b, c) {
return a + b + c;
}
console.log(sum.apply(null, [1, 2, 3])); // 6
推荐场景:
- 参数数量不确定,直接用数组传递最方便。
- 常用于"借用"数组方法处理类数组对象。
function toArray() {
return Array.prototype.slice.apply(arguments);
}
console.log(toArray(1, 2, 3)); // [1, 2, 3]
注意事项:
- apply的this规则和call一致。
- ES6后,很多场景可以用扩展运算符(...)替代apply。
3. bind:返回新函数,this永久绑定
用法简介:
bind不会立即执行函数,而是返回一个永久绑定this的新函数。
const obj = { name: '小明' };
function showName() {
console.log(this.name);
}
const boundShow = showName.bind(obj);
boundShow(); // 小明
推荐场景:
- 需要延迟执行、定时器、事件回调等场景。
- React/Vue等框架中,常用来绑定组件方法的this。
注意事项:
- bind返回的新函数,this无法再被改变。
- 绑定参数后,调用时还可以继续追加参数(柯里化)。
function add(a, b) { return a + b; }
const add5 = add.bind(null, 5);
console.log(add5(10)); // 15
三兄弟的区别和选择建议
- call:参数挨个传,立即执行。
- apply:参数打包成数组,立即执行。
- bind:返回新函数,this永久绑定,延迟执行。
实际开发中,call和apply用来"借用"方法、动态切换上下文最方便;bind适合需要延迟执行、回调、定时器等场景。
个人理解:
this绑定三兄弟,掌握好用法,开发效率直接起飞。别让this"反向拿捏"你,灵活运用,才能写出优雅又健壮的代码。遇到this混乱时,别慌,回头看看这三兄弟,准没错!
如果觉得有用,记得收藏点赞,咱们下篇见!