5种正确处理JS的this指向的方式

5种正确处理JS的this指向的方式

我喜欢在JS中更改函数执行上下文的指向,也称为 this 指向。

例如,咱们可以在类数组对象上使用数组方法:

const reduce = Array.prototype.reduce;function sumArgs() {  return reduce.call(arguments, (sum, value) => {    return sum += value;  });}sumArgs(1, 2, 3); // => 6

登录后复制

另一方面,this 很难把握。

咱们经常会发现自己用的 this 指向不正确。下面的教你如何简单地将 this 绑定到所需的值。

【相关课程推荐:JavaScript视频教程】

在开始之前,我需要一个辅助函数execute(func),它仅执行作为参数提供的函数。

function execute(func) {  return func();}execute(function() { return 10 }); // => 10

登录后复制

现在,继续理解围绕this错误的本质:方法分离。

1. 方法分离问题

假设有一个类Person包含字段firstName和lastName。此外,它还有一个方法getFullName(),该方法返回此人的全名。如下所示:

function Person(firstName, lastName) {  this.firstName = firstName;  this.lastName = lastName;  this.getFullName = function() {    this === agent; // => true    return `${this.firstName} ${this.lastName}`;  }}const agent = new Person('前端', '小智');agent.getFullName(); // => '前端 小智'

登录后复制

可以看到Person函数作为构造函数被调用:new Person(‘前端’, ‘小智’)。 函数内部的 this 表示新创建的实例。

getfullname()返回此人的全名:’前端 小智’。正如预期的那样,getFullName()方法内的 this 等于agent。

如果辅助函数执行agent.getFullName方法会发生什么:

execute(agent.getFullName); // => 'undefined undefined'

登录后复制

执行结果不正确:’undefined undefined’,这是 this 指向不正确导致的问题。

现在在getFullName() 方法中,this的值是全局对象(浏览器环境中的 window )。 this 等于 window,${window.firstName} ${window.lastName} 执行结果是 ‘undefined undefined’。

发生这种情况是因为在调用execute(agent.getFullName)时该方法与对象分离。 基本上发生的只是常规函数调用(不是方法调用):

execute(agent.getFullName); // => 'undefined undefined'// 等价于:const getFullNameSeparated = agent.getFullName;execute(getFullNameSeparated); // => 'undefined undefined'

登录后复制

这个就是所谓的方法从它的对象中分离出来,当方法被分离,然后执行时,this 与原始对象没有连接。

1、为了确保方法内部的this指向正确的对象,必须这样做

2、以属性访问器的形式执行方法:agent.getFullName()或者静态地将this绑定到包含的对象(使用箭头函数、.bind()方法等)

方法分离问题,以及由此导致this指向不正确,一般会在下面的几种情况中出现:

回调

// `methodHandler()`中的`this`是全局对象setTimeout(object.handlerMethod, 1000);

登录后复制

在设置事件处理程序时

// React: `methodHandler()`中的`this`是全局对象

登录后复制

接着介绍一些有用的方法,即如果方法与对象分离,如何使this指向所需的对象。

2. 关闭上下文

保持this指向类实例的最简单方法是使用一个额外的变量self:

function Person(firstName, lastName) {  this.firstName = firstName;  this.lastName = lastName;  const self = this;  this.getFullName = function() {    self === agent; // => true    return `${self.firstName} ${self.lastName}`;  }}const agent = new Person('前端', '小智');agent.getFullName();        // => '前端 小智'execute(agent.getFullName); // => '前端 小智'

登录后复制

getFullName()静态地关闭self变量,有效地对this进行手动绑定。

现在,当调用execute(agent.getFullName)时,一切工作正常,因为getFullName()方法内 this 总是指向正确的值。

3. 使用箭头函数

有没有办法在没有附加变量的情况下静态绑定this? 是的,这正是箭头函数的作用。

使用箭头函数重构Person:

function Person(firstName, lastName) {  this.firstName = firstName;  this.lastName = lastName;  this.getFullName = () => `${this.firstName} ${this.lastName}`;}const agent = new Person('前端', '小智');agent.getFullName();        // => '前端 小智'execute(agent.getFullName); // => '前端 小智'

登录后复制

箭头函数以词法方式绑定this。 简单来说,它使用来自其定义的外部函数this的值。

建议在需要使用外部函数上下文的所有情况下都使用箭头函数。

4. 绑定上下文

现在让咱们更进一步,使用ES6中的类重构Person。

class Person {  constructor(firstName, lastName) {    this.firstName = firstName;    this.lastName = lastName;  }  getFullName() {    return `${this.firstName} ${this.lastName}`;  }}const agent = new Person('前端', '小智');agent.getFullName();        // => '前端 小智'execute(agent.getFullName); // => 'undefined undefined'

登录后复制

不幸的是,即使使用新的类语法,execute(agent.getFullName)仍然返回“undefined undefined”。

在类的情况下,使用附加的变量self或箭头函数来修复this的指向是行不通的。

但是有一个涉及bind()方法的技巧,它将方法的上下文绑定到构造函数中:

class Person {  constructor(firstName, lastName) {    this.firstName = firstName;    this.lastName = lastName;    this.getFullName = this.getFullName.bind(this);  }  getFullName() {    return `${this.firstName} ${this.lastName}`;  }}const agent = new Person('前端', '小智');agent.getFullName();        // => '前端 小智'execute(agent.getFullName); // => '前端 小智'

登录后复制

构造函数中的this.getFullName = this.getFullName.bind(this)将方法getFullName()绑定到类实例。

execute(agent.getFullName) 按预期工作,返回’前端 小智’。

5. 胖箭头方法

bind 方式有点太过冗长,咱们可以使用胖箭头的方式:

class Person {  constructor(firstName, lastName) {    this.firstName = firstName;    this.lastName = lastName;  }  getFullName = () => {    return `${this.firstName} ${this.lastName}`;  }}const agent = new Person('前端', '小智');agent.getFullName();        // => '前端 小智'execute(agent.getFullName); // => '前端 小智'

登录后复制

胖箭头方法getFullName =() =>{…}绑定到类实例,即使将方法与其对象分离。

这种方法是在类中绑定this的最有效和最简洁的方法。

6. 总结

与对象分离的方法会产生 this 指向不正确问题。静态地绑定this,可以手动使用一个附加变量self来保存正确的上下文对象。然而,更好的替代方法是使用箭头函数,其本质上是为了在词法上绑定this。

在类中,可以使用bind()方法手动绑定构造函数中的类方法。当然如果你不用使用 bind 这种冗长方式,也可以使用简洁方便的胖箭头表示方法。

原文:https://github.com/valentinogagliardi/Little-JavaScript-Book/blob/v1.0.0/manuscript/chapter5.md

本文来自 js教程 栏目,欢迎学习!

以上就是5种正确处理JS的this指向的方式的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2729748.html

(0)
上一篇 2025年3月8日 00:09:28
下一篇 2025年3月1日 13:56:00

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 50个JavaScript面试和解答(收藏)

    问题1:Java和JavaScript有什么不同 JavaJavaScript Java是一种OOP编程语言。JavaScript是一种OOP脚本语言。它创建在虚拟机或浏览器中运行的应用程序。代码在浏览器或node环境上运行。需要编译Jav…

    2025年3月8日 编程技术
    200
  • 详解JS箭头函数

    在js中,箭头函数可以像普通函数一样以多种方式使用。但是,它们一般用于需要匿名函数表达式,例如回调函数。 下面示例显示举例箭头函数作为回调函数,尤其是对于map(), filter(), reduce(), sort()等数组方法。 con…

    2025年3月8日
    200
  • Window对象在前端领域的角色

    特殊的window 提起window,在网页当中很常见,比如像这样: window.onload=function(){//执行函数体} 登录后复制 这段代码的意思是当网页内容加载完成后要做什么。 在js的领域,window对象有着双重角色…

    2025年3月8日
    200
  • 详解JavaScript中Switch语句的用法

    除了if … else之外,javascript还有一个称为switch语句的功能。 switch是一种条件语句,它将针对多种可能的情况评估表达式,并根据匹配的情况执行一个或多个代码块。 switch语句与包含许多其他if块的条…

    2025年3月8日
    200
  • 4个开发React应用的实用技巧

    【相关专题推荐:react面试题(2020)】 背景 Hooks 自推出以来就很火, 它改变了我们编写React 代码的方式, 有助于我们写更简洁的代码。 今天这边文章不是说Hooks的,Hooks之外, 还有很多实用的技巧可以帮助我们编写…

    2025年3月8日
    200
  • 深入了解JavaScript中的原型和继承

    本文主要讲了原型如何在JavaScript中工作,以及如何通过[Prototype]所有对象共享的隐藏属性链接对象属性和方法;以及如何创建自定义构造函数以及原型继承如何工作以传递属性和方法值。 介绍 javascript是一种基于原型的语言…

    2025年3月8日
    200
  • ES6 Map原理分析

    es6的map的键可以是任意的数据结构,并且不重复。 那么map的底层原理是啥呢? Map利用链表,hash的思想来实现。 首先,Map可以实现删除,而且删除的数据可以是中间的值。而链表的优势就是在中间的任意位置添加,删除元素都非常快,不需…

    2025年3月8日
    200
  • JS中this究竟指向什么?

    1、this 的奥秘 很多时候, JS 中的 this 对于咱们的初学者很容易产生困惑不解。 this 的功能很强大,但需要一定付出才能慢慢理解它。 【相关课程推荐:JavaScript视频教程】 对Java、PHP或其他标准语言来看,th…

    2025年3月8日 编程技术
    200
  • 深入理解JavaScript的并发模型和事件循环机制

    我们知道js语言是串行执行、阻塞式、事件驱动的,那么它又是怎么支持并发处理数据的呢? “单线程”语言 在浏览器实现中,每个单页都是一个独立进程,其中包含了JS引擎、GUI界面渲染、事件触发、定时触发器、异步HTTP请…

    2025年3月8日 编程技术
    200
  • 深入学习JavaScript之DOM

    通过html dom,可访问javascript html文档的所有元素。下面本篇文章就来给大家介绍一下,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 DOM能干啥? ● JavaScript 能够改变页面中的所有 HTM…

    2025年3月8日
    200

发表回复

登录后才能评论