js的this绑定规则以及箭头函数

目录

  • 调用位置
  • 默认绑定
  • 隐式绑定
    • 隐式丢失
  • 显式绑定
    • call
    • apply
    • bind
  • new绑定
  • 装箱
  • 绑定优先级
  • this规则之外
    • 忽略显式绑定
    • 间接函数引用
  • 箭头函数

调用位置

从字面意思上来理解,this似乎是指向自己的
然而在JavaScript中,this并不是绑定到自身
可以看这一个例子

        function foo(num) {
            console.log("num:" + num)
            this.count++
        }
        foo.count = 0
        for (var i = 0; i < 10; i++) {
            if (i > 5) {
                foo(i)
            }
        }
        console.log(foo.count)

结果
结果

显然从字面意思来理解this指向自身是错误的认知
事实上this并不是编写时绑定的,而是运行时绑定
我们判断this会绑定到什么首先就要分析它的调用位置

        function foo() {
            bar()//此时的调用栈为:全局--》foo--》bar
            function bar() {
                baz()//此时的调用栈为:全局--》foo--》bar--》baz
                function baz() {

                }
            }
        }
        foo()//此时的调用栈为:全局--》foo

在寻找到它的调用位置之后我们就需要判断这里的this适用于以下四条规则中的哪一条

默认绑定

独立调用函数时适用此条,也可以看成当其他三条规则都不适用时适用这条规则
独立函数调用可以看成函数没有被绑定到某个对象上进行调用
例如下面这个例子

        function foo() {
            console.log(this)
        }
        foo()

结果
结果

此时的this绑定了全局对象window
值得注意的是,在严格模式下,这里的this会绑定到undefined

隐式绑定

另一种比较常见的绑定方式为通过某个对象调用

        function foo() {
            console.log(this)
        }
        var obj = {
            name: "obj",
            foo: foo
        }
        obj.foo()

结果
结果
此时的this绑定到了obj对象上了

隐式丢失

被隐式绑定的this有时也会应用默认绑定规则
例如下面这段代码

        function foo() {
            console.log(this)
        }
        var obj = {
            name: "obj",
            foo: foo
        }
        var bar = obj.foo
        bar()

结果
可以看到this绑定到了window上,这就是隐式丢失

显式绑定

在上面的代码中我们可以看到隐式绑定也会有可能出现隐式丢失的现象,为了确保我们的this能正确的绑定到我们想要的对象上可以使用显式绑定
显式绑定可以通过传递参数的形式来把this绑定到参数
显示绑定有具体三种方式

call

call方法需要传入一个参数来作为this的绑定对象,如果函数需要参数则在后面用逗号隔开

        function foo(name, age) {
            console.log(this)
            console.log(name + " " + age)
        }
        var obj = {
            name: "obj",
        }
        foo.call(obj, "张三", 18)

结果
结果
这里可以看到this绑定到了obj上了
注意:call方法是立即执行

apply

apply方式与call方法相似,但传递参数的方式不同

        function foo(name, age) {
            console.log(this)
            console.log(name + " " + age)
        }
        var obj = {
            name: "obj",
        }
        foo.apply(obj, ["张三", 18])

结果
结果
这里可以看到this绑定到了obj上了
注意:apply方法也是立即执行的

bind

无论是apply绑定或者是call绑定,都不能完全解决this绑定丢失问题
当将函数作为参数传递给其他函数之后,很难知道其他函数会怎么调用这个函数
函数的this指向此时也不受你控制
为了解决这个问题,我们可以使用bind方法

        function foo() {
            console.log(this)
        }
        function bar(fn) {
            fn.call(obj)
        }
        var obj = {
            name: "obj",
        }
        bar(foo.bind(window))

结果
结果
bind方法不会立即执行函数,而是会返回一个新函数
新函数的this将会指向你所指定的对象
以后this的指向也始终会是预期

new绑定

当我们使用new关键字时,会执行以下几件事情

  1. 创建一个空对象
  2. 将_空对象_的this绑定到这个空对象
  3. 执行函数体里的代码
        function foo() {
            console.log(this)
            this.a = 2
        }
        var obj = {
            name: "obj",
        }
        var bar = new foo()
        console.log(bar.a)

结果
结果

可以看到此时的this已经绑定到了foo

装箱

无论是call还是apply还是bind,当我们传入一个原始值(如数字字符串)时会发生什么呢

        function foo() {
            console.log(this)
            this.a = 2
        }
        var obj = {
            name: "obj",
        }
        foo.call(123)
        foo.apply("123")

结果
结果
得到的结论就是如果你传入了一个原始值来当作this的绑定对象,这个原始值会被转换成它的对象形式
new Number()new String()等等
这通常被称为装箱

绑定优先级

当一个函数涉及了多条规则,规则与规则之间则会按照自己的优先级生效

  1. 毋庸置疑的是默认绑定优先级最低,是其他规则都不适用情况下的兜底条款

  2. 显示绑定优先级高于隐式绑定

        function foo() {
            console.log(this.name)
            this.a = 2
        }
        var obj = {
            name: "obj",
            foo: foo
        }
        var obj2 = {
            name: "obj2",
            foo: foo
        }
        obj.foo.call(obj2)
    

    结果
    结果

  3. new绑定比隐式绑定优先级高

        function foo() {
            this.a = 2
        }
        var obj = {
            name: "obj",
            a: 4,
            foo: foo
        }
        var obj2 = new obj.foo()
        console.log(obj2.a)
    

    结果
    结果

  4. new绑定无法与call/apply方法一起使用,但我们可以通过与bind方法比较来得到结果

        function foo() {
            console.log(this)
        }
        var obj = {
            name: "obj",
        }
        var obj2 = foo.bind(obj)
        new obj2
    

    结果
    结果
    我们可以知道new绑定优先级高于显式绑定

this规则之外

在现实使用中,我们总有些语法超出了规则之外

忽略显式绑定

当传入的参数是null或者为undefined时,这个显式绑定忽略,使用默认绑定

        function foo() {
            console.log(this)
        }
        foo.call(null)
        foo.call(undefined)

结果
结果

间接函数引用

创建一个函数的间接引用,这种情况适用默认规则

        function foo() {
            console.log(this)
        }
        var obj = {
            foo: foo
        }
        var obj2 = {
            name: "obj2"
        };
        (obj2.foo = obj.foo)()

结果
结果

箭头函数

ES6中提出了一种新函数,他的名字叫箭头函数
箭头函数中,其实并没有this
所以并不适用上面提到的四条规则
箭头函数中的this是由其外部作用域来决定的
当箭头函数中遇到this时,箭头函数便会去它的外层作用域寻找

        var obj = {
            bar: function () {
                var foo = () => {
                    console.log(this)
                }
                return foo
            }
        }
        var baz = obj.bar()
        baz()

结果
结果

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PyTorch翻译官网教程6-AUTOMATIC DIFFERENTIATION WITH TORCH.AUTOGRAD

官网链接 Automatic Differentiation with torch.autograd — PyTorch Tutorials 2.0.1cu117 documentation 使用TORCH.AUTOGRAD 自动微分 当训练神经网络时&#xff0c;最常用的算法是方向传播算法。在该算法中&#xff0c;根据损失函数与给定参数的梯度来调整模型参数&…

Python程序设计基础:列表与元组(二)

文章目录 一、数值列表的生成1、通过input()函数输入创建列表2、通过list()函数转换3、列表生成式4、数值列表的几种统计计算 二、元组1、元组的定义2、元组的操作3、元组作为列表元素 三、转换函数1、元组和列表之间的转换2、字符串和列表之间的转换3、split()方法 一、数值列…

2024考研408-操作系统 第二章-进程与线程 学习笔记

文章目录 前言一、进程1.1、进程的概念、组成与特征1.1.1、进程的概念1.1.2、进程的组成认识PCB认识程序段与数据段&#xff08;包含进程实体概念&#xff09; 1.1.3、进程的特征知识回顾与重要考点 1.2、进程的状态、状态间的转换和组织方式1.2.1、进程的状态进程的五种状态详…

RandLA-Net 复现

GPU3090 CUDA12 1、代码 [github地址] git clone --depth1 https://github.com/QingyongHu/RandLA-Net && cd RandLA-Net 2、虚拟环境中配置&#xff1a; 在跑代码的时候出现错误&#xff1a;open3d.so文件中函数报错。查看open3d版本发现不是要求的0.3版本&#xff…

设计模式 ~ 工厂模式

工厂模式 工厂模式是一种设计模式&#xff0c;指在通过使用工厂函数或构造函数来创建对象&#xff1b; 它提供了一种灵活的方式来创建对象实例&#xff0c;而无需直接调用构造函数或使用new关键字&#xff1b; 可以分类&#xff0c;解耦&#xff1b; 可以扩展多个类&#xff0…

【Spring——Spring的基础与创建】

目录 &#x1f367;1. 什么是 Spring &#xff1f; &#x1fad6;1.1 容器 &#x1f359;1.2 IoC &#x1f97d;1.3 汽车类——传统写法 &#x1f358;1.4 汽车类——IoC 写法 &#x1f32d;2. 配置 maven 国内源 &#x1f32e;2.1 在设置中勾选文件 &#x1f364;2.2 在…

【网站建设】HTTP/HTTPS 是什么?有什么区别?

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;目前学习C/C、算法、Java等方向&#xff0c;一个正在慢慢前行的普通人。 &#x1f3c0;系列专栏&#xff1a;陈童学的日记 &#x1f4a1;其他专栏&#xff1a;CSTL&#xff0c;感…

自定义程序包不存在的解决方法

方案一&#xff1a; 在pom文件中加入以下代码 <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.4.2</version><configuration><skipTests>true</sk…

openResty的Redis模块踩坑记录

OpenResty提供了操作Redis的模块&#xff0c;我们只要引入该模块就能直接使用。说是这样说&#xff0c;但是实践起来好像并不太顺利。 1.设置了密码的redis&#xff0c;lua业务逻辑中需要添加身份认证代码 网上很多资料、文章似乎都是没有设置redis密码&#xff0c;说来也奇怪…

fileinclude

前提知识&#xff1a; filter伪协议 include函数用php://filter伪协议来绕过 题目&#xff1a; 打开题目 页面显示如图&#xff0c;可以知道flag在flag.php中&#xff0c;还知道当前页面的绝对路径 先查看源代码 15行$lan用$_cookie传参&#xff0c;可以修改cookie值从而控制…

探索非洲专线物流的新时代_国际物流供应链管理平台_箱讯科技

随着全球化的发展&#xff0c;非洲作为一个充满机遇和挑战的大陆&#xff0c;吸引着越来越多的企业和投资者。然而&#xff0c;由于非洲的地理复杂性和基础设施不完善&#xff0c;物流问题一直是制约非洲发展的瓶颈之一。为了解决这一问题&#xff0c;非洲专线物流应运而生。本…

网络原理之传输层与网络层重点协议

目录 传输层重点协议 TCP协议 TCP协议段格式 TCP原理 确认应答机制&#xff08;安全机制&#xff09; 超时重传机制&#xff08;安全机制&#xff09; 连接管理机制&#xff08;安全机制&#xff09; 滑动窗口&#xff08;效率机制&#xff09; 流量控制&#xff08;安…

数字IC笔试面试常考问题及答案汇总(内含各岗位大厂题目)

经历了无数的笔试面试之后&#xff0c;不知道大家有没有发现数字IC的笔试面试还是有很多共通之处和规律可循的。所以一定要掌握笔试面试常考的问题。 数字IC笔试面试常考问题及答案汇总&#xff08;文末可领全部哦~&#xff09; 验证方向&#xff08;部分题目&#xff09; Q1…

数据可视化分析,2023结婚全品类消费趋势洞察报告

结婚消费与人们的关系密切相关。结婚是一个重要的人生事件&#xff0c;往往伴随着大量的消费。人们倾向于在婚礼仪式、婚纱摄影、宴会等方面进行豪华的投资&#xff0c;以展示社会地位和个人品味。此外&#xff0c;结婚还涉及到婚戒、婚庆、蜜月旅行等费用。然而&#xff0c;随…

Jenkins+Robot 接口自动化测试

目录 前言&#xff1a; 设计目标 项目说明 目录结构 配置 jenkins 1.安装插件 2.配置项目 前言&#xff1a; JenkinsRobot是一种常见的接口自动化测试方案&#xff0c;可以实现自动化的接口测试和持续集成。Jenkins是一个流行的持续集成工具&#xff0c;而Robot Framew…

【5G PHY】5G 调制与编码策略(MCS)介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

Cisco学习笔记(CCNA)——Internetworking

Internetworking Internetworking Basics 什么是网络&#xff1f; 计算机网络&#xff1a;具有独立功能的多台计算机及其外部设备&#xff0c;通过通信线路连接起来 网络设备 Hub&#xff08;集线器&#xff09; 优点&#xff1a;便宜、操作简单 缺点&#xff1a;共享型、…

Kubernetes(K8s)常用命令大全:熟练编排更完美

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

react 升级

1、查看react版本 当前开发项目的react版本从哪里看呢&#xff1f;其实就在package.json文件中&#xff0c;搜索"react"&#xff0c;即可看到版本号 2、输入命令npm info react查看最新的react版本 3、执行命令 npm install --save react18.2.0 react-dom18.2.0 4…

Docker 部署 Jenkins (一)

Docker 部署 Jenkins (一) 一. 安装 jenkins $ mkdir -p /home/tester/data/docker/jenkins $ vim jenkins:lts-jdk11.sh./jenkins:lts-jdk11.sh 内容 #! /bin/bash mkdir -p /home/tester/data/docker/jenkins/jenkins_homesudo chown -R 1000:1000 /home/tester/data/dock…