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

news2024/11/25 12:20:15

目录

  • 调用位置
  • 默认绑定
  • 隐式绑定
    • 隐式丢失
  • 显式绑定
    • 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()

结果
结果

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

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

相关文章

蓝牙HID模式下输出中文原理简介

目录 前言一、蓝牙和HID简介二、Unicode编码简介三、Windows下alt键code编码输出中文四、蓝牙HID模式下实现在手机上输入中文的原理 前言 最近在使用蓝牙模组&#xff0c;对于蓝牙模组如何输出中文的原理不太清楚&#xff0c;所以找了一些资料简单学习了下&#xff0c;总结如下…

目标检测——FasterRCNN原理与实现

目录 网络工作流程数据加载模型加载模型预测过程RPN获取候选区域FastRCNN进行目标检测 模型结构详解backboneRPN网络anchorsRPN分类RPN回归Proposal层 ROIPooling目标分类与回归 FasterRCNN的训练RPN网络的训练正负样本标记RPN网络的损失函数训练过程实现正负样本设置损失函数 …

Kubernetes 使用 helm 部署 NFS Provisioner

文章目录 1. 介绍2. 预备条件3. 部署 nfs4. 部署 NFS subdir external provisioner4.1 集群配置 containerd 代理4.2 配置代理堡垒机通过 kubeconfig 部署 1. 介绍 NFS subdir external provisioner 使用现有且已配置的NFS 服务器来支持通过持久卷声明动态配置 Kubernetes 持久…

大模型基础知识汇总

本文总结大模型相关基础知识&#xff0c;用于大模型学习入门 &#xff08;持续更新中…&#xff09; 文章目录 NLP 基础知识传统 NLP 知识NLU 与 NLG 各种任务的差异 Transformer 相关知识Pre Norm与Post Norm的区别&#xff1f;Bert 预训练过程手写 transformer 的 attention …

从0到1:跑团小程序开发心得笔记

背景介绍 随着健康意识的兴起&#xff0c;越来越多的人选择加入跑步俱乐部&#xff0c;不仅体验到了运动的乐趣&#xff0c;也感受到了人生的不同色&#xff0c;那么通过小程序&#xff0c;把俱乐部搬到手机上&#xff0c;通过小程序了解俱乐部动态和运动常识&#xff0c;可以…

C++自定义信号和QML的槽函数建立连接

0x00 在C代码在定义一个信号函数&#xff1a;“void sendData2UI(QString msg);”&#xff0c;该函数主要是将接收到的UDP消息发送到QML界面中 #ifndef UDPCLI_H #define UDPCLI_H#include <QObject> #include <QUdpSocket> #include <QString>class UdpCli …

【Netty】NIO基础(三大组件)

文章目录 三大组件Channel & BufferSelector ByteBufferByteBuffer 正确使用姿势ByteBuffer 内部结构ByteBuffer 常见方法分配空间向 buffer 写入数据从 buffer 读取数据mark 和 reset 字符串与 ByteBuffer 互转Scattering ReadsGathering Writes粘包、半包分析 附&#xf…

《啊哈算法》第一章--排序

文章目录 前言一、排序算法二、桶排序三、冒泡排序三、快速排序总结 前言 今年蓝桥杯没有拿到省一&#xff0c;所以就决定沉下心来学习算法&#xff0c;为了使得算法的学习更加稳固&#xff0c;所以就拿起了&#xff0c;最基础的且最经典的一本算法书《啊哈算法》&#xff0c;…

Redis进阶底层原理- 持久化

Redis作为基于内存的缓存数据库&#xff0c;就会存在断电即失的问题&#xff0c;所以数据的持久化是非常重要的。Redis随着版本升级迭代&#xff0c;持久化技术也在不断的升级&#xff0c;&#xff08;从最开始的RDB&#xff0c;到的Redis1.1版本加入AOF&#xff0c;3.0版本支持…

全志F1C200S嵌入式驱动开发(sd卡驱动)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 说是sd卡,其实是micro sd卡,或者称之为tf卡更合适。一般的soc都支持从tf卡启动,所以用tf卡来学习soc、驱动和linux,对新人来说是比较合适的。前面我们已经用sd卡构建了一个类似…

uniapp:针对与富文本解析的几种方法

第一章、富文本的解析方法 1.1 uniapp自带组件&#xff1a;rich-text <rich-text :nodes"nodes"></rich-text> 1.2 v-html <view v-html"item.content"></view> 1.3 uview组件&#xff1a;u-parse <u-parse :content&quo…

学习babylon.js --- [3] 开启https

babylonjs提供WebVR功能&#xff0c;但是使用这个功能得用https&#xff0c;本文讲述如何使用自签名证书来开启https&#xff0c;基于第二篇文章中搭建的工程。 一 生成自签名证书 首先要安装openssl&#xff0c;这个去网上搜下就行了。安装完之后在终端下输入openssl回车可以…

DeepC 实用教程(三)环境数据

目 录 一、前言二、风谱/风剖三、洋流四、波浪4.1 规则波浪4.2 随机波浪谱 五、方向六、海床属性七、位置7.1 创建位置7.2 规则波时域条件7.3 随机波时域条件7.4 波浪散布图7.4.1 散布图分块7.4.2 时域条件 八、参考文献 一、前言 SESAM &#xff08;Super Element Structure A…

y0usef靶场详解

y0usef靶场详解 靶机感悟&#xff1a;对于这个靶机并没有太多的难点&#xff0c;也没有的别多的绊子&#xff0c;就是猜测下一步是什么&#xff0c;耐心的去思考怎么才能进行到下一步。 靶机下载地址&#xff1a;https://download.vulnhub.com/y0usef/y0usef.ova 这个靶机是…

每天一点Python——day55

#第五十五天Python内置数据结构&#xff1a;列表、字典、元组 本次学另外一种数据结构&#xff1a;集合 集合也是可变类型序列 重点&#xff1a;集合里面没有value&#xff0c;只有键&#xff0c;采用也是哈希函数#如图&#xff1a; #集合与字典的对比字典&#xff1a; 字典{ke…

Java 提供的线程安全集合

一、CopyOnWrite&#xff08;COW算法的容器&#xff09; 最终一致性、写分离思想。 用Volatile修饰&#xff0c;每次直接从内存地址中读取&#xff0c;读取时不加锁。 写时用显式锁整个容器&#xff08;防止其它写线程&#xff09;&#xff0c;然后拷贝一份副本&#xff0c;对…

【NLP】transformers的位置编码

一、背景 本文是“实现的变压器”系列的第二篇。它从头开始引入位置编码。然后,它

【Linux | Shell】结构化命令 - if 语句

目录 一、概述二、if-then 语句三、if-then-else 语句四、if-then-elif 语句五、嵌套 if 语句 一、概述 前面文章介绍了一些Shell脚本的基础知识&#xff0c;也了解了怎样构建一个shell脚本文件&#xff0c;让shell脚本执行一些基础的指令&#xff0c;但都是从上到下依次执行的…

少年侠客【InsCode Stable Diffusion美图活动一期】

少年侠客【InsCode Stable Diffusion美图活动一期】 文章目录 Stable Diffusion 模型在线使用地址第一张图第二张图第三张图第四张图第五张图第六章图 一、InsCode Stable Diffusion 体验1.1 界面很友好1.2 小小体验一下1.3 体验感受 二、如何在InsCode给Stable Diffusion安装L…

车载软件架构 —— 闲聊几句AUTOSAR OS(九)

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 没有人关注你。也无需有人关注你。你必须承认自己的价值,你不能站在他人的角度来反对自己。人生在世,最怕的就是把别人的眼光当成自己生活的唯一标…