一文搞定JavaScript不同场景中 this 的指向问题

 更新时间:2026年07月21日 09:59:42   作者:mONESY  
this 是 JavaScript 中最容易混淆的核心关键字之一,严格模式、普通函数、对象方法、构造函数、事件处理、call/apply/bind、箭头函数都会彻底改变 this 的指向,本文结合完整示例代码拆解每一种场景,理清所有边界

this 是 JavaScript 中最容易混淆的核心关键字之一,它不是在定义函数时确定,而是在函数执行调用时动态绑定。严格模式、普通函数、对象方法、构造函数、事件处理、call/apply/bind、箭头函数都会彻底改变 this 的指向,本文结合完整示例代码拆解每一种场景,理清所有边界。

一、基础前置知识:严格模式与全局对象

1. 全局 window 与变量声明差异

"use strict"; // 严格模式
var name = "王五"; // var声明变量会挂载到window全局对象
let test = "测试"; // let/const 不会污染window
console.log(window.name); // 王五
console.log(window.test); // undefined
  • var:全局声明自动绑定 window,造成全局污染;
  • let / const:存在块级作用域,不挂载全局;
  • 严格模式 "use strict" :禁止普通函数中 this 指向 window,普通函数直接调用时 this = undefined,避免全局篡改。

2. 核心底层规则

this 绑定优先级(从低到高):全局默认绑定 < 对象隐式绑定 < call/apply 显式绑定 < bind 硬绑定 < 构造函数 new < 箭头函数(不绑定 this,继承外层)

二、场景 1:普通独立函数调用(默认绑定)

非严格模式

普通函数直接执行,this 指向全局 window:

function normalFn() {
  console.log(this); // window
  console.log(this.name); // 王五
}
normalFn();

严格模式

开启 "use strict" 后,普通函数 this 为 undefined,访问全局变量会直接报错,防止误操作全局:

"use strict";
function normalFn() {
  console.log(this); // undefined
  console.log(this.name); // Uncaught TypeError
}
normalFn();

坑点:对象方法提取为独立函数

把对象方法赋值给变量后调用,会降级为普通函数,丢失原有对象绑定:

let obj = {
  name: "张三",
  say: function () {
    console.log(this.name);
  }
};
const fn = obj.say; // 仅拿到函数引用,脱离对象
fn(); // 严格模式下undefined,非严格模式输出全局name

三、场景 2:作为对象方法调用(隐式绑定)

当函数作为对象的属性(方法)执行时,this 直接指向调用该方法的对象:

let obj = {
  name: "张三",
  say: function () {
    console.log(this); // {name: "张三", say: ƒ}
    console.log(this.name); // 张三
  }
};
obj.say();

关键规则

谁调用方法,this 就指向谁,链式调用只看最后调用的对象:

let a = { name: "A", fn: function() { console.log(this.name) } }
let b = { name: "B", a: a }
b.a.fn(); // 输出A,this指向a,不是b

四、场景 3:手动修改 this 指向 — call /apply/bind(显式绑定)

三个方法都能手动指定函数内 this,核心区别在是否立即执行与传参格式。

1. call (obj, 参数 1, 参数 2...)

立即执行函数,参数逐个传递

let obj2 = { name: "李四" };
obj.say.call(obj2); // this指向obj2,输出 李四
obj.speak.call(obj2, "你好", "我是李四");

2. apply (obj, [参数数组])

立即执行函数,参数统一放进数组传递,其余逻辑和 call 完全一致

obj.speak.apply(obj2, ["你好", "我是李四"]);

3. bind(obj)

不会立即执行,返回一个全新永久绑定 this 的函数,适合异步场景(事件、定时器)

const fn2 = obj.speak.bind(obj2);
fn2("你好", "我是李四"); // 新函数执行,this永远固定obj2

实战:事件绑定中 bind 的使用

事件监听器会自动修改函数 this 为触发 DOM 元素,如果需要固定 this,只能用 bind:

const oForm = document.querySelector('.add-items');
function addItem(e) {
  console.log(this.name); // 想要拿到obj的name
  e.preventDefault();
}
// call/apply会直接执行函数,不能丢给addEventListener
const addItemBind = addItem.bind(obj); 
oForm.addEventListener('submit', addItemBind);

call /apply/bind 对比表

方法是否立即执行传参形式返回值使用场景
call逐个传入函数执行结果参数数量少、临时调用
apply数组传入函数执行结果参数为数组、动态传参
bind新函数调用时传参永久绑定 this 的新函数事件、定时器、异步回调

五、场景 4:DOM 事件处理函数中的 this

给 DOM 绑定事件,触发时处理函数内 this 固定指向触发事件的 DOM 元素,等同于 e.target(特殊冒泡场景除外):

document.querySelector('.lnk').addEventListener('click', goBaidu);
function goBaidu(e) {
  console.log(this); // <a class="lnk"> 触发点击的a标签
  e.preventDefault(); // 阻止a标签默认跳转
}
  • 不使用 bind:this = DOM 元素
  • 使用 bind 绑定自定义对象:this = bind 传入的对象

六、场景 5:构造函数 new 调用

函数通过 new 关键字当作构造函数执行时,底层做 4 件事:

  1. 创建空新对象;
  2. 将新对象绑定为函数内 this;
  3. 执行构造函数;
  4. 若无手动 return 对象,自动返回新对象。
function Person(name) {
  this.name = name; // this指向新建实例
}
const p = new Person("小明");
console.log(p.name); // 小明

七、场景 6:箭头函数 — 无独立 this

箭头函数不存在自己的 this,不会绑定上述任何规则,会直接继承定义时外层作用域的 this:

  1. 不能用作构造函数(new 会报错);
  2. call/apply/bind 无法修改箭头函数 this;
  3. 事件回调、定时器中常用,保留外层 this;
let testObj = {
  name: "箭头测试",
  fn: () => {
    console.log(this.name); // 外层全局name:王五,不会指向testObj
  }
}
testObj.fn();

八、完整优先级总结(判断 this 万能流程)

拿到函数调用代码,从上到下匹配第一条规则即可:

  1. 是否为箭头函数:this = 定义时外层 this;
  2. 是否用 new 构造调用:this = 新建实例;
  3. 是否使用 bind 硬绑定:this = bind 传入对象;
  4. 是否使用 call/apply:this = 传入的第一个参数;
  5. 是否作为对象方法调用:this = 调用方法的对象;
  6. 普通独立调用:严格模式 this=undefined,否则 window。

九、完整可运行示例代码(整合文中全部逻辑)

"use strict";
// 全局var挂载window
var name = "王五";
let oForm = document.querySelector('.add-items');

let obj = {
  name: "张三",
  say: function () {
    console.log("say的this:", this);
    console.log("name:", this.name)
  },
  speak: function (a, b) {
    console.log("参数:", a, b);
    console.log("speak的this:", this);
  }
}
let obj2 = { name: "李四" };

// 1. 对象方法调用
obj.say();

// 2. 提取为普通函数调用
const fn = obj.say;
// fn(); // 严格模式 this = undefined

// 3. call / apply 临时修改this
obj.say.call(obj2);
obj.say.apply(obj2);
obj.speak.call(obj2, '你好', '我是李四');
obj.speak.apply(obj2, ['你好', '我是李四']);

// 4. bind 返回新函数,永久绑定this
const fn2 = obj.speak.bind(obj2);
fn2('你好', '我是李四');

// 5. bind用于事件监听
function addItem(e) {
  console.log("表单提交this:", this);
  e.preventDefault();
}
const addItemBind = addItem.bind(obj);
oForm.addEventListener('submit', addItemBind);

// 6. DOM事件原生this指向DOM
document.querySelector('.lnk').addEventListener('click', goBaidu);
function goBaidu(e) {
  console.log("点击链接this:", this);
  e.preventDefault();
}

// 7. 箭头函数无自身this
const arrowTest = () => {
  console.log("箭头函数this:", this);
}
arrowTest();

十、写在最后

this 的难点不在于概念复杂,而在于多场景绑定规则互相覆盖。日常开发记住两个核心技巧:

  1. 事件、定时器需要固定自定义 this → 使用 bind;
  2. 需要复用外层上下文 this(如定时器、嵌套回调)→ 使用箭头函数;
  3. 临时切换对象调用函数 → 使用 call / apply。分清每种调用方式对应的绑定规则,就能彻底规避 this 指向错乱的 bug。

到此这篇关于一文搞定JavaScript不同场景中 this 的指向问题的文章就介绍到这了,更多相关JavaScript this指向问题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JS如何调用WebAssembly编译出来的.wasm文件

    JS如何调用WebAssembly编译出来的.wasm文件

    这篇文章主要介绍了关于WebAssembly编译出来的.wasm文件js如何调用,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • jsPDF生成pdf后在网页展示实例

    jsPDF生成pdf后在网页展示实例

    本文为大家介绍下jsPDF生成pdf后如何在网页展示,下面有个不错示例,大家可以参考下
    2014-01-01
  • javascript实现鼠标拖动改变层大小的方法

    javascript实现鼠标拖动改变层大小的方法

    这篇文章主要介绍了javascript实现鼠标拖动改变层大小的方法,涉及javascript操作鼠标事件及样式的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-04-04
  • 原生js实现放大镜效果

    原生js实现放大镜效果

    本文主要分享了原生js封装实现放大镜效果的示例代码,具有一定的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • 实现抖音两个旋转小球的loading技巧实例

    实现抖音两个旋转小球的loading技巧实例

    这篇文章主要为大家介绍了实现抖音两个旋转小球的loading技巧实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • JS的for循环中的var 和 let详解

    JS的for循环中的var 和 let详解

    在js的嵌套for循环异步执行,声明i和使用i获取到的变量 都要用 let 声明,不要用var,这篇文章主要介绍了JS的for循环中的var和let,需要的朋友可以参考下
    2024-05-05
  • JS onmousemove鼠标移动坐标接龙DIV效果实例

    JS onmousemove鼠标移动坐标接龙DIV效果实例

    这篇文章主要介绍了JS onmousemove鼠标移动坐标接龙DIV效果实例,有需要的朋友可以参考一下
    2013-12-12
  • Javascript 函数的四种调用模式

    Javascript 函数的四种调用模式

    这篇文章主要介绍了Javascript 函数的四种调用模式的相关资料,需要的朋友可以参考下
    2016-11-11
  • CKeditor4 字体颜色功能配置方法教程

    CKeditor4 字体颜色功能配置方法教程

    这篇文章主要介绍了CKeditor4 字体颜色功能配置方法,结合图文与实例的形式分析了CKeditor4 添加字体颜色扩展功能的相关实现步骤与操作技巧,需要的朋友可以参考下
    2019-06-06
  • Webpack介绍和基本使用指南

    Webpack介绍和基本使用指南

    Webpack 本身功能比较少,只能处理 js 资源,一旦遇到 css 等其他资源就会报错,本文给大家讲解Webpack介绍和基本使用指南,感兴趣的朋友一起看看吧
    2024-02-02

最新评论