一文拆解JavaScript中this的五种绑定规则

 更新时间:2026年07月03日 08:34:15   作者:先吃饱再说  
this是JavaScript最让人头疼的概念,本文将从一段 setTimeout 的惊喜代码入手,拆解 this 的五种绑定规则,帮你彻底告别 this 困惑

摘要this 是 JavaScript 最让人头疼的概念。本文从一段 setTimeout 的“惊喜”代码入手,拆解 this 的五种绑定规则——普通函数、对象方法、事件处理、call/apply/bind 手动绑定、箭头函数——帮你彻底告别 this 困惑。

一段让你怀疑人生的this代码

先来看这段代码:

var name = '梅西';
let obj = {
    name: '姆巴佩',
    say: function(){
        setTimeout(function() {
            console.log(this.name);
        }, 1000);
    }
}
obj.say(); // 输出:梅西

你本期待看到“姆巴佩”,结果却是“梅西”。

setTimeout 里的函数明明是写在 obj 里面的,为什么 this 指向了外面的 梅西

这段代码覆盖了 this 的多个关键规则:普通函数、对象方法、setTimeout 异步执行、全局变量污染。理解了它,就理解了一大半的 this 规则。

我们从最基础的规则开始拆解。

规则一:默认绑定——普通函数调用

当一个函数作为普通函数(不是对象方法、不是构造函数、不是事件处理函数)被调用时,this 指向全局对象(浏览器中是 window,Node.js 中是 global)。

var name = '小许';
function say() {
    console.log(this.name);
}
const fn = obj.say;
fn(); // 输出:小许(this 指向 window)

这里有一个完整的示例:

let obj = {
    name: "大许",
    say: function() {
        console.log(this);
        console.log(`${this.name}`);
    }
}
const fn = obj.say; // 引用式赋值
fn(); // 这里函数是作为普通函数被调用,this 指向全局 window

obj.say 本来是对象的方法,但通过引用赋值给 fn 后,调用方式变成了“普通函数调用”,this 丢失了原来的指向,回到了默认绑定。

如何在 window 上找到 name

var name = '梅西'; // var 会挂载到 window
// 或
window.name = '梅西';

let 和 const 声明的变量不会挂载到 window,即使是在全局作用域。common.js 的注释明确说明了这一点:

var 声明会在变量环境中,会直接作为全局对象 window 的属性。let 声明会在词法环境中,即使是全局变量也是与 window 对象隔离开的。

严格模式下的区别

可以在js文件第一行加上一句:"use strict"; 来强制切换为严格模式

严格模式下,普通函数调用时,this 无法通过默认绑定绑到外层作用域的全局对象上,这时 this 的值会变成 undefined

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

这其实是一种“纠错”设计——避免你在普通函数中误用全局对象。

规则二:隐式绑定——作为对象方法调用

当函数作为对象的方法被调用时,this 指向调用该方法的对象。

let obj = {
    name: "姆巴佩",
    say: function() {
        console.log(this.name);
    }
}
obj.say(); // "姆巴佩"

这是最直观的场景:谁调用了函数,this 就指向谁

高度总结:

this 是一个指针,指向函数的调用者。函数运行时指定(不是声明的时候),不是像变量那样在编译阶段指定。

规则三:事件处理函数绑定——this 指向触发元素

当函数作为事件处理函数被调用时,this 指向触发事件的元素对象。

document.querySelector('.lnk').addEventListener('click', goBaidu);

function goBaidu(e) {
    console.log(this); // 指向 <a href="..." rel="external nofollow" > 元素
    e.preventDefault(); // 阻止跳转
}

作为事件处理函数被调用,this 指向触发事件的元素对象。

关键点

  • 事件处理函数的 this 不是 window,也不是定义函数的对象——而是触发事件的 DOM 元素。
  • 这就是为什么 addEventListener 里的回调函数不能用箭头函数,因为它会丢失 this(后面会讲)。

为什么e.preventDefault()很重要?

背景说明:

form 表单提交会默认提交,即使没有指定 action,也会在本页面提交,导致刷新页面。e.preventDefault() 阻止默认行为,页面不会刷新,可以后续在 JS 中处理数据提交,实现动态页面。

同样,<a href=""> 链接也会默认跳转,用 e.preventDefault() 阻止。

规则四:手动绑定——call、apply、bind

callapplybind 可以手动指定函数执行时的 this 指向。

方法是否立即执行传参方式返回
call立即执行逐个传递函数执行结果
apply立即执行数组传递函数执行结果
bind不执行,返回新函数逐个传递新函数
let obj = { name: "大许" };
let obj2 = { name: "大祥" };

obj.say.call(obj2);   // this → obj2,立即执行
obj.say.apply(obj2);  // 同上,传参用数组
const newSay = obj.say.bind(obj2); // 返回新函数,不立即执行
newSay();             // 执行新函数,this → obj2

// 有参数的情况
obj.speak.call(obj2, 1, 2);      // 逐个传
obj.speak.apply(obj2, [1, 2]);   // 数组传
const fn2 = obj.speak.bind(obj2);
fn2(1, 2);

bind的典型场景:异步回调

关键场景:

bind 手动指定 this,返回一个全新的函数(不是立即执行的),使用场景是异步时的手动修改 this 指向。

回到开头的 setTimeout 问题,bind 可以解决:

setTimeout((function() {
    console.log(this.name); // this 被绑定到 obj
}).bind(obj), 1000);

因为 bind 返回新函数且不立即执行,正好满足 setTimeout 延迟执行的场景。

规则五:箭头函数——没有 this 的 this

箭头函数不创建自己的 this,它会从外层作用域中“继承” this

let obj3 = {
    name: '姆巴佩',
    say: function(){
        setTimeout(() => {
            console.log(this.name); // "姆巴佩"
        }, 1000);
    }
}
obj3.say();

箭头函数里没有 this,所以它不会“丢失” this——它直接使用了外层 say 函数的 this(指向 obj3)。

箭头函数是简化函数,它根本不考虑 this,所以写在箭头函数中的 this 和写在箭头函数外的 this 是一样的。

这就是为什么 setTimeout 中用箭头函数能拿到正确的 this——它根本不创建自己的 this,直接从外层取。

一点总结

调用方式this 指向
普通函数调用(非严格模式)全局对象(window)
普通函数调用(严格模式)undefined
对象方法调用调用该方法的对象
事件处理函数触发事件的 DOM 元素
构造函数(new新创建的实例对象
call / apply / bind手动指定的对象
箭头函数外层作用域的 this(无自己的 this

一句话心法this 不是你在哪里写的,而是你在哪里怎么调用的。箭头函数是唯一的例外——它根本没有 this

互动讨论

  1. setTimeout 的第一个例子中,为什么 var name = '梅西' 能影响输出,而用 let name = '梅西' 就不行?
  2. 事件处理函数中,为什么不能用箭头函数替代普通函数?  试想如果 addEventListener('click', () => {})this 会指向什么?
  3. call 和 apply 有什么区别?  什么场景下用 apply 更合适?
  4. bind 和 call 最大的区别是什么?  为什么异步场景需要 bind
  5. 为什么 JavaScript 要设计 this 这个机制?  如果完全没有 this,代码会变成什么样?

一点心得:this 不是 bug,它是一种设计选择——让函数在不同的调用上下文中复用。理解了“谁调用,指向谁”这条铁律,再加上箭头函数这个例外,你就掌握了 this 的核心。

到此这篇关于一文拆解JavaScript中this的五种绑定规则的文章就介绍到这了,更多相关JavaScript this绑定规则内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用JS获取当前地理位置方法汇总

    使用JS获取当前地理位置方法汇总

    这篇文章主要介绍了使用JS获取当前地理位置方法汇总,需要的朋友可以参考下
    2014-12-12
  • 解析javascript中鼠标滚轮事件

    解析javascript中鼠标滚轮事件

    这篇文章主要给大家详细介绍了javascript中鼠标滚轮事件,图文并茂,十分的详细,有需要的小伙伴可以参考下。
    2015-05-05
  • JavaScript之移动端H5生成图片解决方案讲解

    JavaScript之移动端H5生成图片解决方案讲解

    这篇文章主要介绍了JavaScript之移动端H5生成图片解决方案讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • 可插入图片的TEXT文本框

    可插入图片的TEXT文本框

    这篇文章主要介绍了可插入图片的TEXT文本框,有需要的朋友可以参考一下
    2013-12-12
  • JavaScript实现tab栏切换效果

    JavaScript实现tab栏切换效果

    这篇文章主要为大家详细介绍了JavaScript实现tab栏切换效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-03-03
  • JavaScript设置失效时间清除本地存储数据的几种方法

    JavaScript设置失效时间清除本地存储数据的几种方法

    这篇文章介绍了如何使用localStorage和sessionStorage设置失效时间来清除本地存储的数据,并提供了一种自动清除过期数据的方法,需要的朋友可以参考下
    2025-02-02
  • JS算法教程之字符串去重与字符串反转

    JS算法教程之字符串去重与字符串反转

    这篇文章主要给大家介绍了关于JS算法教程之字符串去重与字符串反转的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • JavaScript实现Flash炫光波动特效

    JavaScript实现Flash炫光波动特效

    JavaScript写的炫光波动效果,看到一些Flash效果不错,用JS也模拟一下,还有很多不完善的地方,给各位参考参考。
    2015-05-05
  • js如何在字符串中查找某个字符的位置

    js如何在字符串中查找某个字符的位置

    这篇文章主要给大家介绍了关于js如何在字符串中查找某个字符的位置的相关资料,在JavaScript中我们经常需要对字符串进行各种操作,包括查找包含特定字符的字符串,需要的朋友可以参考下
    2023-11-11
  • JavaScript实现复制文章自动添加版权

    JavaScript实现复制文章自动添加版权

    自己辛辛苦苦写的文章,轻易就被别人复制-粘贴去了,是不是很伤心呢?小编今天给大家整理了两个方法,让别人复制自己的文章时,自动在文章的结尾添加自己的版权信息。
    2016-08-08

最新评论