author: 专注前端开发,分享JavaScript干货
title: JavaScript高级③|this指向详解,5种绑定规则彻底搞懂
update: 2026-04-28
tags: JavaScript,this,call,apply,bind,箭头函数,this绑定,前端进阶
作者:专注前端开发,分享JavaScript干货
更新时间:2026年4月
适合人群:有JS基础,经常被this指向搞晕的开发者
前言:this为什么难?
this不像传统语言指向当前类的实例,JS的this在函数调用时才确定。
掌握5种绑定规则,就能100%判断this指向。
一、默认绑定(独立函数调用)
functionfoo(){console.log(this);}// 浏览器环境foo();// Window(非严格模式)// undefined(严格模式 'use strict')// Node.js环境foo();// global(非严格模式)// undefined(严格模式)二、隐式绑定(作为对象方法调用)
constobj={name:"张三",sayHi(){console.log(this.name);}};obj.sayHi();// "张三"(this指向调用者obj)// ⚠️ 隐式丢失:把方法赋值给变量后,this会丢失constfn=obj.sayHi;fn();// undefined(this指向全局/undefined)// 常见场景:回调函数setTimeout(obj.sayHi,1000);// undefined(隐式丢失)三、显式绑定(call / apply / bind)
functiongreet(greeting,punctuation){console.log(`${greeting},${this.name}${punctuation}`);}constperson={name:"张三"};// call:立即调用,参数逐个传greet.call(person,"你好","!");// "你好,张三!"// apply:立即调用,参数用数组传greet.apply(person,["嗨","~"]);// "嗨,张三~"// bind:返回新函数,不立即调用constboundGreet=greet.bind(person,"早上好");boundGreet("。");// "早上好,张三。"四、new绑定(构造函数调用)
functionPerson(name){// new调用时,this指向新创建的对象this.name=name;this.sayHi=function(){console.log(`我是${this.name}`);};}constp=newPerson("张三");p.sayHi();// "我是张三"(this指向p)// new做了什么:// 1. 创建一个空对象 {}// 2. 将对象的 __proto__ 指向构造函数的 prototype// 3. 将构造函数中的 this 指向这个对象// 4. 执行构造函数代码// 5. 如果构造函数没有返回对象,则返回这个新对象五、箭头函数(没有自己的this)
constobj={name:"张三",// 普通函数:this指向调用者sayHi1(){console.log(this.name);},// 箭头函数:this继承外层作用域sayHi2:()=>{console.log(this.name);// this指向外层(这里是全局)}};obj.sayHi1();// "张三" ✅obj.sayHi2();// undefined ❌// 箭头函数的经典场景:回调函数constobj2={name:"李四",items:[1,2,3],process(){// ❌ 普通函数:this指向有问题this.items.forEach(function(item){console.log(this.name,item);// undefined, 1...});// ✅ 箭头函数:this继承process的thisthis.items.forEach((item)=>{console.log(this.name,item);// "李四", 1...});}};obj2.process();六、绑定优先级
new绑定 > 显式绑定(call/apply/bind)> 隐式绑定(对象方法)> 默认绑定functionfoo(){console.log(this);}constobj1={name:"obj1",foo};constobj2={name:"obj2",foo};// 隐式绑定obj1.foo();// obj1// 显式绑定(优先级更高)obj1.foo.call(obj2);// obj2// new绑定(优先级最高)constboundFoo=foo.bind(obj1);// 显式绑定constinstance=newboundFoo();// new绑定,this指向新实例console.log(instance);// foo {} (不是obj1)七、实战:修正this指向
// 场景1:定时器中的thisconstobj={count:0,start(){// ❌ setTimeout的回调是独立调用,this指向全局setTimeout(function(){this.count++;console.log(this.count);// NaN(this指向Window)},1000);// ✅ 方案1:用箭头函数setTimeout(()=>{this.count++;console.log(this.count);// 1, 2, 3...},1000);// ✅ 方案2:用bind绑定setTimeout(function(){this.count++;console.log(this.count);}.bind(this),1000);}};obj.start();// 场景2:事件处理函数button.addEventListener("click",function(){// this指向button元素console.log(this);// <button>});button.addEventListener("click",()=>{// this指向外层作用域(这里可能是Window)console.log(this);// Window ❌});八、知识卡
| 规则 | 说明 |
|---|---|
| 默认绑定 | 独立调用,this指向全局/undefined |
| 隐式绑定 | 对象方法调用,this指向对象 |
| 显式绑定 | call/apply/bind,手动指定this |
| new绑定 | 构造函数调用,this指向新对象 |
| 箭头函数 | 没有this,继承外层作用域的this |
九、课后作业
- 分析下面代码输出并解释:
constobj={name:"test",foo(){console.log(this.name);}};constfn=obj.foo;fn(); - 用三种方式实现:在setTimeout回调中正确访问obj的name
- 实现一个
call的模拟函数myCall(fn, context, ...args)
有问题欢迎评论区留言,大家一起讨论!
标签:JavaScript | this | call | apply | bind | 箭头函数 | this绑定 | 前端进阶