javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > js改变this指向

一文详解js中如何改变this指向

作者:辛-夷

在JavaScript中,关键字this是指向当前执行上下文的对象,它的指向取决于函数被调用的方式,这篇文章主要介绍了js中如何改变this指向的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

1.this指向

什么是this指向?

在 JavaScript中,this的指向取决于函数被调用的方式,而非定义的位置

1.1常见的this

  1. 独立函数
    函数独立调用时,this指向全局对象(浏览器中为 window,Node.js中为global)。
function show() {
  console.log(this); // window(非严格模式)
}
show();

严格模式下为undefined

function show() {
  "use strict"
  console.log(this); // undefined
}
show(); // 如果window.show()那么此时的this指向的就是window
  1. 对象函数
    函数作为对象方法调用时,this 指向调用它的对象
const user = {
  name: "Alice",
  greet() {
    console.log(`Hello, ${this.name}!`); // Hello, Alice!
  }
};
user.greet();

方法被分离后调用会导致this丢失

const func = user.greet;
func(); // ❌ 错误:this 丢失(指向 window/undefined)
  1. 箭头函数
    箭头函数的this定义:箭头函数的this是在定义函数时绑定的,不是在执行过程中绑定的。简单的说,函数在定义时,this就继承了定义函数的对象。
    箭头函数内的this就是箭头函数外的那个this为什么?
    注意:箭头函数没有自己的this
const obj = {
  name: "Dave",
  regularFunc: function() {
      console.log(this.name); // Dave(隐式绑定)
  },
  arrowFunc: () => {
      console.log(this.name); // 空(继承外层 this)window上没有name
  }
};
obj.regularFunc();
obj.arrowFunc();
let name = "123";
let person = {
  name: "456",
  fn1: function() {
      // 这边的this和下面的setTimeout函数下的this相等
      let that = this;
      setTimeout(() => {
          console.log(this.name, that === this); // '456' true
      }, 0);
  },
  fn2: function() {
      // 这边的this和下面的setTimeout函数下的this不相等
      let that = this;
      setTimeout(function() {
          console.log(this.name, that === this); // '123' false
      }, 0);
  },
};
person.fn1(); // '456' true
person.fn2(); // '123' false
  1. DOM节点
    非严格模式
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>最编程 创未来</title>
  </head>
  <body>
    <button>变色</button>
    <script>
      let elements = document.getElementsByTagName("button")[0];
      elements.addEventListener(
        "click",
        function () {
          this.style.backgroundColor = "#A5D9F3";
        },
        false
      );
    </script>
  </body>
</html>

严格模式

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>最编程 创未来</title>
  </head>
  <body>
    <button>变色</button>
    <script>
      'use strict'
      var elements = document.getElementsByTagName("button")[0];
      elements.addEventListener(
        "click",
        function () {
          console.log(this)
          this.style.backgroundColor = "#A5D9F3";
        },
        false
      );
    </script>
  </body>
</html>

5. 内联事件函数

当代码被内联处理函数调用时,它的this指向监听器所在的DOM元素,不区分严格或非严格模式

<button onclick="console.log(this)">点击测试</button> <!-- <button onclick="console.log(this)">点击测试</button> -->

当代码被包括在函数内部执行时,其this指向等同于函数直接调用的情况,即在非严格模式指向全局对象window

<button onclick="(function() { console.log(this) })()">点击测试</button> <!-- Window {window: Window, self: Window, document: document, name: '最编程', location: Location, …} -->

当代码被包括在函数内部执行时,其this指向等同于函数直接调用的情况,在严格模式指向undefined

<button onclick="(function() {'use strict'; console.log(this) })()">点击测试</button> <!-- undefined -->
  1. 构造函数
    构造函数中,this 指向新创建的实例对象Person{}
function Person(name) {
  this.name = name;
}
const charlie = new Person("金小子");
console.log(charlie.name); // 金小子
// 伪代码展示 new 的操作流程
const charlie = new Person("金小子");

// 实际发生的步骤:
// 1. 创建新对象
const tempObj = {};

// 2. 设置原型链
tempObj.__proto__ = Person.prototype;

// 3. 将 this 绑定到新对象并执行构造函数
Person.call(tempObj, "金小子"); // 此时构造函数内的 this = tempObj

// 4. 返回新对象
const charlie = tempObj;

以上就是常见的this指向,那么接下来来看改变this指向的方式。

2. call、apply、bind

JavaScript 的 call、apply 和 bind 都是用于显式绑定函数执行时的 this 指向。

三者核心区别:

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

● apply:立即执行函数,数组形式传递参数

● bind:不立即执行,返回新函数(永久绑定 this 和部分参数)

2.1 call

call

语法

func.call(thisArg, arg1, arg2, ...)  

例子

function greet(message) {
  console.log(`${message}, ${this.name}!`);
}

const person = { name: "Alice" };

// 将 greet 的 this 指向 person,并传递参数  
greet.call(person, "Hello"); // 输出: "Hello, Alice!"

● greet 中的 this 原本指向全局(如 window),但通过 call 将 this 绑定到 person 对象

● “Hello” 作为参数逐个传递

2.2 apply

语法

func.apply(thisArg, [argsArray])  

示例

function introduce(age, job) {
  console.log(`${this.name} is ${age} years old and works as a ${job}.`);
}

const person = { name: "Bob" };

// 将 introduce 的 this 指向 person,参数通过数组传递  
introduce.apply(person, [30, "developer"]); // 输出: "Bob is 30 years old and works as a developer."

● 参数以数组 [30, “developer”] 形式传递(适合动态参数场景)

● 等同于 introduce.call(person, 30, “developer”)

2.3 bind

语法

const newFunc = func.bind(thisArg, arg1, arg2, ...)  
newFunc()

示例

function logHobby(hobby1, hobby2) {
  console.log(`${this.name} likes ${hobby1} and ${hobby2}.`);
}

const person = { name: "Charlie" };

// 创建新函数,永久绑定 this 和部分参数  
const boundFunc = logHobby.bind(person, "hiking");

// 调用新函数时只需传入剩余参数  
boundFunc("reading"); // 输出: "Charlie likes hiking and reading."

● bind 返回一个新函数 boundFunc,其 this 永久绑定为 person

● “hiking” 被预设为第一个参数,调用时只需传递剩余参数

总结

方法执行时机参数形式是否返回新函数
call立即执行逐个参数 (arg1, arg2)
apply立即执行数组 ([args])
bind延迟执行逐个参数(可部分预设)

🌟 核心总结

this 指向是 JavaScript 中核心且易混淆的知识点,其本质遵循「调用决定指向」的原则(箭头函数除外):

普通函数:this 指向调用它的对象,独立调用时指向全局(严格模式为 undefined);

箭头函数:无自有 this,继承定义时外层作用域的 this;

构造函数 / 事件处理:this 分别指向实例对象、触发事件的 DOM 元素;

显式绑定:call/apply/bind 可强制修改 this 指向,三者仅在「执行时机、参数形式」上有差异(call/apply 立即执行,bind 返回新函数)。

📌 实践建议

日常开发中,优先通过「对象方法调用」「箭头函数」「bind 绑定」明确 this 指向,避免全局 this 污染;

处理动态参数时用 apply,需预设参数 / 延迟执行时用 bind,简单传参优先 call;

严格模式下需格外注意独立函数的 this 指向(变为 undefined),避免意外报错。

🎯 记忆口诀

this 指向:「谁调用,指向谁;箭头函数,找外层;构造 /new,指实例;显式绑定,听 call/apply/bind」;

绑定三兄弟:「call 逐个传,apply 数组传,bind 绑完等调用」。

到此这篇关于js中如何改变this指向的文章就介绍到这了,更多相关js改变this指向内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文