欢迎来到科站长!

JavaScript

当前位置: 主页 > 网络编程 > JavaScript

一篇文章详细讲解JavaScript中的this(普通函数、箭头函数、 函数运用)

时间:2025-07-21 10:15:07|栏目:JavaScript|点击:

前言

this对象:解析器在每次调用函数时,都会向函数内部转递一个隐含的参数,这个参数就是this,this指向的是一个对象,这个对象我们称为函数执行的上下文对象,根据函数调用方式的不同,this会指向不同的对象

一、将根据一下几个方面介绍this的指向问题

  • 全局环境中的 this
  • 函数中的 this
  • 对象方法中的 this
  • 构造函数中的 this
  • 事件处理函数中的 this
  • 箭头函数中的 this

1、全局环境中的this

在全局环境中(不在任何函数或对象内部),this指向全局对象(在浏览器环境中是window,在node.js中是global

1
console.log(this === window); // 在浏览器中输出 true

2、函数中的this

当一个函数被直接调用时,this在非严格模式下指向全局对象(window),在严格模式下指向undefined

JS严格模式:JavaScript在语法和行为上存在一些模糊的特性,可能导致一些不易察觉的错误,为提高代码的质量和可维护性,js引入了严格模式,通过启用一些额外的规则,强制执行更严格的语法和行为。在严格模式下代码中的潜在问题将被捕获并抛出错误,有助于提前发现和修复潜在bug。

1
2
3
4
5
6
7
8
9
10
11
function regularFunction() {
  console.log(this);
}
 
regularFunction(); // 非严格模式下指向 window,严格模式下为 undefined
 
// 演示严格模式下的情况
(function () {
  "use strict";
  regularFunction();
})();

3、对象方法中的this

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

1
2
3
4
5
6
7
8
var person = {
  name: "John",
  sayName: function () {
    console.log(this.name);
  }
};
 
person.sayName(); // 输出 "John",这里的 this 指向 person 对象

4、构造函数中的this

使用new关键字(实例化)调用函数时,该函数被当作构造函数(类),this会指向新创建的对象实例

1
2
3
4
5
6
7
8
9
function Person(name) {
  this.name = name;
  this.sayHello = function () {
    console.log("Hello, I'm " + this.name);
  };
}
 
var john = new Person("John");
john.sayHello(); // 输出 "Hello, I'm John",这里 this 指向 john 实例

构造函数怎么执行创建对象的过程:

  • 调用一个构造函数,他会立即创建一个对象
  • 将新建的对象设置为函数中的this,在构造函数中可以使用this来引用新建的对象
  • 逐行执行函数中的代码
  • 将新建的对象作为返回值返回

在构造函数中,创建对象和返回对象都给我们隐藏了,使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类。我们将通过一个构造函数创建的对象,称为是该类的实例。

5、事件处理函数中的this

在DOM事件处理函数中,this通常指向触发事件的元素。

1
2
3
4
5
6
7
8
9
<button id="myButton">Click me</button>
 
<script>
  var button = document.getElementById("myButton");
  button.onclick = function () {
    console.log(this); // 点击按钮时,这里的 this 指向按钮元素
                      //打印 :<button id="myButton">Click me</button>
  };
</script>

7、箭头函数中的this

箭头函数没有自己的this,它的this继承自外层作用域的this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 普通函数
function outerFunction() {
  this.name = "Outer";
  var innerFunction = function () {
    console.log(this.name);
  };
  innerFunction();
}
 
// 箭头函数
function outerFunctionWithArrow() {
  this.name = "Outer with Arrow";
  var innerFunction = () => {
    console.log(this.name);
  };
  innerFunction();
}
 
new outerFunction(); // 输出 undefined,因为 innerFunction 中的 this 指向全局对象,全局对象没有 name 属性
new outerFunctionWithArrow(); // 输出 "Outer with Arrow",箭头函数的 this 继承自 outerFunctionWithArrow 的 this

二、改变this指向的方法

由于箭头函数的this来自于继承,箭头函数无法使用以下三种方法改变this指向

1、call()方法

  • call 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向
  • 语法: 函数名.call(要改变的 this 指向,要给函数传递的参数1,要给函数传递的参数2, ...)
  • 使用 call 方法的时候:
    1、会立即执行函数
    2、第一个参数是你要改变的函数内部的 this 指向
    3、第二个参数开始,依次是向函数传递参数
1
2
3
4
5
6
7
8
var obj = { name: 'Jack' }
function fn(a, b) {
  console.log(this)
  console.log(a)
  console.log(b)
}
fn(1, 2)
fn.call(obj, 1, 2)
  • fn(1,2) 的时候,函数内部的 this 指向 window(函数被直接调用)
  • fn.call(obj, 1, 2) 的时候,函数内部的 this 就指向了 obj 这个对象

2、apply()方法

  • apply 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向
  • 语法: 函数名.apply(要改变的 this 指向,[要给函数传递的参数1, 要给函数传递的参数2, ...])
  • 使用 call 方法的时候:
    1、会立即执行函数
    2、第一个参数是你要改变的函数内部的 this 指向
    3、第二个参数是一个 数组,数组里面的每一项依次是向函数传递的参数(和call方法的主要区别点)
1
2
3
4
5
6
7
8
var obj = { name: 'Jack' }
function fn(a, b) {
  console.log(this)
  console.log(a)
  console.log(b)
}
fn(1, 2)
fn.apply(obj, [1, 2])
  • fn(1,2) 的时候,函数内部的 this 指向 window(函数被直接调用)
  • fn.call(obj, 1, 2) 的时候,函数内部的 this 就指向了 obj 这个对象

3、bind()方法

  • bind 方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向
  • 和 call / apply 有一些不一样,就是不会立即执行函数,而是返回一个已经改变了 this 指向的函数
  • 语法: var newFn = 函数名.bind(要改变的 this 指向); newFn(传递参数)
1
2
3
4
5
6
7
8
9
var obj = { name: 'Jack' }
function fn(a, b) {
  console.log(this)
  console.log(a)
  console.log(b)
}
fn(1, 2)
var newFn = fn.bind(obj)
newFn(1, 2)
  • bind 调用的时候,不会执行 fn 这个函数,而是返回一个新的函数
  • 这个新的函数就是一个改变了 this 指向以后的 fn 函数
  • fn(1, 2) 的时候 this 指向 window
  • newFn(1, 2) 的时候执行的是一个和 fn 一摸一样的函数,只不过里面的 this 指向改成了 obj

三、回调函数中this指向

这里我们补充一下在回调函数运用中this指向(也是容易混淆的知识点)

1、对象方法作为回调函数

如果回调函数是一个对象的方法,并且是以对象方法的方式传递进去的,那么 this 通常会指向该对象。

1
2
3
4
5
6
7
8
9
var myObject = {
  value: 10,
  callbackFunction: function () {
    console.log(this.value);
  }
};
[1,2,3].forEach(() => {
  myObject.callbackFunction()
});        //输出三个10

在这个例子中,forEach 是数组的方法,myObject.callbackFunction 作为回调函数传递给 forEach。当 forEach 调用这个回调函数时,this 仍然指向 myObject,因为这个函数本质上还是 myObject 的一个方法。

2、箭头函数作为回调函数

箭头函数没有自己的 this,它会继承外层作用域的 this(依据词法作用域规则)。

1
2
3
4
5
6
7
8
function outerFunction() {
  this.name = "Outer";
  var array = [1, 2, 3];
  array.forEach(() => {
    console.log(this.name);  //打印三次Outer
  });
}
new outerFunction();

根据上面两个例子,这里我们介绍一下普通函数箭头函数在确定this指向时的一些区别:

1、普通函数

普通函数在函数定义时会确定函数的作用域,但不会明确函数中this的指向。普通函数中this的指向是在函数被调用时被确定(指向调用者或者全局对象)

2、箭头函数

箭头函数由于其本身不会生成this,其this继承自外层作用域。箭头函数在定义时不仅会确定作用域,而且会捕获外层作用域的this作为自身的this,箭头函数的this在定义时就已经确定,在其后的函数调用时,无论调用箭头函数的是谁它的this指向都不会发生改变。

以上面这个例子为例:

箭头函数定义在 outerFunction 这个函数内部,注意不是定义在 forEach 方法内。具体可以了解一下函数传参的步骤,这里箭头函数是先在 outerFunction 这个函数内部定义,之后才作为参数传给 forEach 方法。箭头函数继承了 outerFunction 函数的this,并在之后被 forEach 方法调用时不会发生改变。

3、回调函数指向全局对象的常见情况

当普通函数作为回调函数,并且这个普通函数是被一个全局函数(如 setTimeout、setInterval)或者在全局作用域中独立调用的函数(没有通过对象来调用)调用时,在非严格模式下,this 通常会指向全局对象。

1
2
3
4
//被一个全局函数调用
setTimeout(function () {
  console.log(this);
}, 1000);
1
2
3
4
5
6
7
8
//在全局作用域中独立调用
  function outer(){
    inner()
  }
  function inner(){
    console.log(this);
  }
  outer()

四、总结与常见错误示例

this指向:1、普通函数:谁调用函数,this就指向谁,没有调用者就指向全局对象Window
2、箭头函数:箭头函数不会创建this,它的this继承自上层作用域中的this

1、案例一

1
2
3
4
5
6
7
8
9
10
11
//回调函数中错误使用this
var person = {
  name: "Eve",
  greetLater: function () {
    setTimeout(function () {
      console.log(this.name); // 此处的function为普通函数,作为setTimeout的参数this指向全局对象
    }, 1000);
  }
};
 
person.greetLater();

此处的function为普通函数,被一个全局函数调用,其this指向全局对象 Window 。

要想输出 Eve ,将此处的普通函数改为箭头函数即可。

1
2
3
4
5
6
7
8
9
10
var person = {
  name: "Eve",
  greetLater: function () {
    setTimeout( ()=> {
      console.log(this.name); // 输出Eve
    }, 1000);
  }
};
 
person.greetLater();

2、案例二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//在嵌套函数中混淆 this 指向
var outer = {
  name: "Outer Object",
  innerFunction: function () {
    var inner = {
      name: "Inner Object",
      nestedFunction: function () {
        console.log(this.name); // 这里 this 指向 inner,而不是 outer
      }
    };
    inner.nestedFunction();
  }
};
 
outer.innerFunction();

nestedFunction 是作为 inner 对象的方法被调用,this指向 inner 对象(根据普通函数 this 指向的规则,当函数作为对象的方法被调用时,this 会指向调用该函数的对象。)

4.2.1、使用外层作用域this的方法

想要访问到 outer 对象的 name 属性,可以使用以下两种方法:

1、保存外层 this 的引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var outer = {
  name: "Outer Object",
  innerFunction: function () {
    var self = this;
    var inner = {
      name: "Inner Object",
      nestedFunction: function () {
        console.log(self.name); // 现在可以访问到 outer 的 name 属性,输出 "Outer Object"
      }
    };
    inner.nestedFunction();
  }
};
 
outer.innerFunction();

在方法的开头先把 this 保存到一个变量中(通常命名为 self 或 that 等),然后在 inner 对象中使用这个保存的变量来访问 outer 对象的属性。

2、使用箭头函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var outer = {
  name: "Outer Object",
  innerFunction: function () {
    var inner = {
      name: "Inner Object",
      nestedFunction: () => {
        console.log(this.name); // 输出 "Outer Object"
      }
    };
    inner.nestedFunction();
  }
};
 
outer.innerFunction();

将 nestedFunction 改为箭头函数,因为箭头函数会继承外层作用域的 this,在这里外层作用域是 outer.innerFunction(),其 this 指向 outer 对象,所以箭头函数里的 this 也能指向 outer 对象。

总结


上一篇:JavaScript中实现Sleep功能及其应用的几种方法

栏    目:JavaScript

下一篇:Vue 3 中 vue-router 的 router.resolve () API详解

本文标题:一篇文章详细讲解JavaScript中的this(普通函数、箭头函数、 函数运用)

本文地址:https://fushidao.cc/wangluobiancheng/23719.html

广告投放 | 联系我们 | 版权申明

申明:本站所有的文章、图片、评论等,均由网友发表或上传并维护或收集自网络,属个人行为,与本站立场无关。

如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

联系QQ:257218569 | 邮箱:257218569@qq.com

Copyright © 2018-2025 科站长 版权所有冀ICP备14023439号