重走前端路JS进阶篇:This 指向与箭头函数

news2025/7/17 14:11:23

JavaScript 高级

This 指向规则

案例

    function foo() {
        console.log(this)
    }
    // 1 调用方式1
    foo();
    // 2 调用方式2 放入对象中调用
    var obj = {
        name: "why",
        foo: foo
    }
    obj.foo()

    // 调用方式三 通过 call/apply 调用
    foo.call("abc")

image-20230223171236633

指向定义

this 是js 给函数的一个绑定值。

  1. 函数在调用时 JavaScript会默认给this绑定一个值;
  2. this的绑定和定义的位置(编写的位置)没有关系;
  3. this的绑定和调用方式以及调用的位置有关系
  4. this是在运行时被绑定的

无严格模式下 为 window 如果打开严格模式 则为 udnefined

this 的绑定规则如下:

  1. 绑定一:默认绑定 PS: 没有绑定到任何对象时 & 函数定义在对象中但是被独立调用 对象也是 window

  2. 绑定二:隐式绑定 PS:由JS 绑定到调用对象 指向对象

  3. 绑定三:new绑定

    • new 执行过程
    • 1 创建空对象
    • 2 修改this 指向为空对象
    • 3 执行函数体代码
    • 没有显示返回非空对象时 默认返回这个对象
  4. 绑定四 显示绑定

    • 如果我们不希望在 对象内部 包含这个函数的引用,同时又希望在这个对象上进行强制调用

    • function foo() {
              console.log(this)
      }   
      var obj = {
               name: "why",
             foo: foo
          }
      foo.call(123)
      
      console 输出内容 {name: 'why', foo: ƒ}
      
    • call/apply 可以帮助我们完成这个效果

额外函数补充

Call / Apply 调用方法 两者区别不大 但是又细微差别

apply

    function foo(name, age, height) {
        console.log("foo 函数this 指向", this);
        console.log("参数:", name, age, height);
    }
 
    // 普通调用  直接入参
    foo("why", 18, 1.22)
    // apply
    // 第一个参数 绑定 this 
    // 第二个参数 传入额外的实参 以数组的形式
    //   foo.apply("apply",["why", 18, 1.22])
    foo.apply("123", ["why", 18, 1.22])

call

    function foo(name, age, height) {
        console.log("foo 函数this 指向", this);
        console.log("参数:", name, age, height);
    }

    // call
    // 第一个参数 绑定 this
    // 后续参数以 参数列表形式 
    foo.call("call", "远目鸟", 18, 12)

两者 相同处 都是调用方法 第一参数都指向this 唯一区别只在后续传入的参数的形势

  • apply 为数组
  • call 为列表 以 , 分割

bind :会创建 绑定函数 我们希望调用foo 的时候总是让this 指向 obj

    function foo() {
        console.log("foo 函数this 指向", this);
    }
    var obj = {
        name: "why"
    }

    // 需求 调用foo时 总是绑定 obj 
    var bar = foo.bind(obj)
    bar()

在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。 实际开发中 使用不多 作为参考 了解即可

内置函数

一般 对于浏览器 的内置函数 或者是第三方框架的 this 指向 我们只能用经验去判断 一个一个去源码或者文档查看和并不现实

This 优先级

  1. 默认绑定 优先级最低
  2. 显式绑定 高于隐式绑定
  3. new 高于隐式绑定 PS:new不能和 call/apply 一起使用
  4. new绑定优先级高于bind
  5. 同显式 bind 优先级高于 call/apply

拓展: 规则之外

**情况一:**如果在显示绑定中,我们传入一个null或者undefined,那么这个显示绑定会被忽略,使用默认规则:

    function foo() {
        console.log("foo 函数this 指向", this);
    }
    var obj = {
        name: "why"
    }

    foo.call(obj)
    foo.call(null)
    foo.call(undefined)

    var bar = foo.bind(obj)
    bar()

但是打开严格模式 就会可以使用基础属性 直接显示 null 或者 undefined

**情况二:**创建一个函数的 间接引用,这种情况使用默认绑定规则。

  • 这种情况 (obj2.foo = obj1.foo) 会使用默认规则 指向 window
    var obj1 = {
        name: "obj1",
        foo: function () {
            console.log("foo 函数this 指向", this);
        }
    }

    var obj2 = {
        name: "obj2"
    };

    obj1.foo();
    (obj2.foo = obj1.foo)();

**情况三:**箭头函数

  • 箭头函数不会绑定this、arguments属性
  • 箭头函数不能作为构造函数来使用
    // {} 是执行体
    var arrFn = () => { }
    // 指向的是对象 需要加小括号才可以做到
    var arrFn = () => ({ name: "why" })

箭头函数

  • 基本写法

    • ():函数的参数

    • {}:函数的执行体

    •     var foo3 = (name, age) => {
            console.log("箭头函数的函数体")
            console.log(name, age)
          }
      
  • 优化写法

    • 只有一个参数时, 可以省略()

          names.forEach(item => {
             console.log(item)
          })
      
    • 只有一行代码时, 可以省略{}

      names.forEach(item => console.log(item))
      
    • 只要一行代码时, 表达式的返回值会作为箭头函数默认返回值, 所以可以省略return

      var newNums = nums.filter(item => item % 2 === 0)
      var newNums = nums.filter(item => item % 2 === 0)
      
    • 如果箭头函数默认返回的是对象, 在省略{}的时候, 对象必须使用()包裹 () => ({name: “why”})

          var arrFn = () => ["abc", "cba"]
          var arrFn = () => {} // 注意: 这里是{}执行体
          var arrFn = () => ({ name: "why" })
          console.log(arrFn())
      

箭头函数不使用this的四种标准规则(也就是不绑定this),而是根据外层作用域来决定this。

我们来看一个模拟网络请求的案例:

  • 这里我使用setTimeout来模拟网络请求,请求到数据后如何可以存放到data中呢?
  • 我们需要拿到obj对象,设置data;
  • 但是直接拿到的this是window,我们需要在外层定义:var _this = this
  • _在setTimeout的回调函数中使用_this就代表了obj对象
  • 但是如果使用箭头函数根据特性他会向上寻找this 省去了_this = this的操作
    var obj = {
        data: [],
        getData: function () {
            request("/11", (res) => {
                this.data = [].concat(res)
            })
        }
    }

    function request(url, callbackFn) {
        var res = ["abc", "cba", "nba"]
        callbackFn(res)
    }
    obj.getData()

总结

  1. this的指向问题与优先级 是踏入JS的敲门砖,如果不先系统了解之后使用的时候可能会出现奇怪的错误
  2. 使用ES6的语法 箭头函数 提前熟悉ES6语法可以提升开发效率

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/369386.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL零基础入门学习(十)

SQL零基础入门学习(九) SQL CREATE DATABASE 语句 CREATE DATABASE 语句用于创建数据库。 SQL CREATE DATABASE 语法 CREATE DATABASE dbname;SQL CREATE DATABASE 实例 下面的 SQL 语句创建一个名为 “my_db” 的数据库: CREATE DATAB…

内网solr全文搜索服务器,快解析一步映射让外网访问

Solr,指apache solr,其全称为Search On Lucene Replication。Solr,是一个高性能,采用java开发,基于Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可…

算法练习-栈和队列(二)

算法练习-栈和队列(二) 文章目录算法练习-栈和队列(二)1.计算器1.1 题目1.2 题解2. 删除字符串中所有相邻重复项2.1 题目2.2 题解3 栈的压入、弹出序列3.1 题目3.2 题解4 每日温度4.1 题目4.2 题解4.2.1 暴力解法(超出时间限制)4.2.2单调栈5 接雨水&…

i2c子系统

i2c 硬件协议 Linux 应用层读写i2c 数据 在Linux系统上,不仅可以在内核中使用 i2c 总线发送、接收数据,同时也支持应用层使用i2c 总线发送、接收。 如果在内核中使能了drivers/i2c/i2c-dev.c 配置,内核就会为每一个i2c 控制器生成一个/dev/…

如何使评论具有可操作性?取悦客户的指南

永远不要低估承认的力量。 当品牌与客户互动时,认可会带来更好的关系和更好的沟通。与买家和客户建立更多的个人联系意味着品牌需要证明他们支持他们的产品和客户。评论是利用客户分享他们的故事的那些时刻的绝佳机会。 为什么评论在 SaaS 中至关重要 在 B2B 软件的…

robot framework + python实现http接口自动化测试框架

前言 下周即将展开一个http接口测试的需求,刚刚完成的java类接口测试工作中,由于之前犯懒,没有提前搭建好自动化回归测试框架,以至于后期rd每修改一个bug,经常导致之前没有问题的case又产生了bug,所以需要…

金仓数据库安装

一、麒麟操作系统安装金仓数据库 操作系统 DISTRIB_IDKylin DISTRIB_RELEASEV10 DISTRIB_CODENAMEjuniper 按照安装文档的步骤安装,记得记住设置的数据库的用户名、密码 二、window安装连接数据库的工具软件 三、jdbc连接数据库 (1)连接工…

分享10个非常不错的封面设计模板

封面设计很关键,这决定了用户是否愿意更进一步了解作品或者产品。从布局结构到文字排版和配色,好的封面设计一定是涉及多方面的综合加持。今天给大家整理很多优质的封面设计案例,可以免费商用,包括了:磨砂风格封面、玻…

nodejs+vue停车场停车位短租系统vscode

目 录前端技术:nodejsvueelementui 前端:HTML5,CSS3、JavaScript、VUE 1、 node_modules文件夹(有npn install产生) 这文件夹就是在创建完项目后,cd到项目目录执行npm install后生成的文件夹,下载了项目需要的依赖项。 2、…

LoRaWAN模块在智能停车中的应用

智能停车是指利用自动驾驶技术,帮助驾驶员迅速找到可使用的停车位,并为驾驶员提供准确的驾驶路径。智能停车系统的高级体系结构包括四大要素:(1)“车位锁”的驻车刹车。(2)与“车位锁”相连的一种网络关卡。(3)一个获取停车场状况并发布一个控…

设计模式—策略(Strategy)模式

一、概述策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化使用策略模式可以把行为和环境分割开来。环境类负责维持和查询行为类,…

时序预测 | MATLAB实现LSTM-SVR(长短期记忆神经网络-支持向量机)时间序列预测

时序预测 | MATLAB实现LSTM-SVR(长短期记忆神经网络-支持向量机)时间序列预测 目录时序预测 | MATLAB实现LSTM-SVR(长短期记忆神经网络-支持向量机)时间序列预测效果一览基本介绍模型介绍LSTM模型SVR模型LSTM-SVR模型程序设计参考资料致谢效果一览 基本介绍 本次运行测试环境MA…

黑客入门(超级详细版)

据我了解,“黑客”大体上应该分为“正”、“邪”两类,正派黑客依靠自己掌握的知识帮助系统管理员找出系统中的漏洞并加以完善,而邪派黑客则是通过各种黑客技能对系统进行攻击、入侵或者做其他一些有害于网络的事情,因为邪派黑客所…

利用sim函数在m文件里运行Simulink模型

目录前言准备参考文章第一步第二步第三步前言 最近在使用Simulink做仿真的时候,需要在m文件里运行Simulink模型,用到了sim函数,记录一下 准备 MATLAB R2022a 参考文章 matlab函数sim,matlab sim函数究竟是怎么用的? Matlab中…

在SNAP中用sentinel-1数据制作DEM

在SNAP中用sentinel-1数据制作DEM0 SNAP 简介1 SNAP和snaphu的安装1.1 SNAP安装1.2 snaphu安装1.2.1 Windows系统安装snaphu1.2.2 Linux系统中安装snaphu2 基于InSAR技术制作DEM的基本原理3 数据下载,包括sentinel-1 SLC数据、参考DEM数据、精密轨道数据3.1 sentine…

LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法

LeetCode经典算法题:井字游戏优势洗牌Dota2参议院java解法 井字游戏优势洗牌Dota2参议院1 井字游戏题目描述解题思路与代码2 优势洗牌题目描述解题思路与代码3 Dota2参议院题目描述解题思路与代码1 井字游戏 题目描述 用字符串数组作为井字游戏的游戏板 board&…

Linux 服务器CPU超高如何快速定位

前言 在生产环境中有时会遇见服务器CPU超高的问题,特别是重大版本发布后如果有内存泄露很容出现CPU超高,严重可能会达到100%。现在我们使用的服务器都是多核CPU,当出现CPU告警我们需要及时发现问题代码并处置,不然严重情况下会导致…

【阿旭机器学习实战】【36】糖尿病预测---决策树建模及其可视化

【阿旭机器学习实战】系列文章主要介绍机器学习的各种算法模型及其实战案例,欢迎点赞,关注共同学习交流。 【阿旭机器学习实战】【36】糖尿病预测—决策树建模及其可视化 目录【阿旭机器学习实战】【36】糖尿病预测---决策树建模及其可视化1. 导入数据并…

Datacom-HCIE考试经验分享

我是誉天Datacom秦同学。作为誉天众多通过Datacom-HCIE考试的学员之一,我感到很荣幸。 首先说说自学的感受吧: 我是从2020年开始接触网络行业的,听单位的前辈说华为的HCIE认证是行业含金量最高的证书,从那时起心里就种下了一个“I…

用 Visual Studio 升级 .NET 项目

现在,你已可以使用 Visual Studio 将所有 .NET 应用程序升级到最新版本的 .NET!这一功能可以从 Visual Studio 扩展包中获取,它会升级你的 .NET Framework 或 .NET Core 网页和桌面应用程序。一些项目类型仍正在开发中并将在不久的未来推出&a…