JavaScript中的this指向绑定规则(超全)

JavaScript中的this指向绑定规则(超全)

1.1 为什么需要this?

为什么需要this?

在常见的编程语言中,几乎都有this这个关键字(Objective-C中使用的是self),但是在JavaScript中的this和常见的面向对象语言中的this不太一样

  • 常见面向对象的编程语言中,比如Java,C++,Swift、Dart等等一系列语言中,this通常只会出现在方法
  • 也就是你需要有一个类,类中的方法(特别是实例方法)中,this代表的是当前调用对象

但是JavaScript中的this更加灵活无论是它出现的位置还是它代表的含义

我们来看一下编写一个obj的对象,有this和没有this的区别

image-20241122185112728

从上面我们可以看出:this的作用就是提高的代码的复用性,不用随着对象名字的改变而改变,直接this指向当前对象即可

1.2 目前掌握两个this的判断方法

1.2.1 以默认的方式调用一个函数,this指向window

  1. 代码示例:
  function foo(name,age) {console.log(arguments)console.log(this)}foo("123","hahah","xiix")//默认调用,没有对象引用function sayHello(name) {console.log(this)}
  1. 结果分析

image-20241122185717441

  1. 思考题:下述代码fn调用的this指向什么?
    var obj = {name:"why",running:function() {console.log(this)console.log(this===obj)},eating:function() {console.log("eaintg~",this.name)},eaing:function() {console.log("studying~",this.name)}}//题目一obj.running()var fn = obj.runningfn()

答案:默认调用,指向window对象

image-20241122190132320

    function bar() {console.log(this)}var obj = {name:"why","bar":bar}obj.bar()//谁调用它,对象就会指向哪个

答案:指向obj对象,被obj对象调用

image-20241122190309008

1.2.2 通过对象调用,this指向调用的对象

  1. 代码案例
 var obj = {name:"why",running:function() {console.log(this)//指向的就是objconsole.log(this===obj)},eating:function() {console.log(this)},eaing:function() {console.log(this)}}obj.running()

结果分析:被obj对象调用,所以指向obj这个对象

image-20241122190447415

  1. 思考题:下述代码调用的this指向什么?
    function bar() {console.log(this)}var obj = {name:"why","bar":bar}obj.bar()//谁调用它,对象就会指向哪个

答案:指向obj对象,被obj对象调用

image-20241122190309008

1.3 this到底指向什么呢?

我们先来看一个令人困惑的问题:

  • 定义一个函数,我们采用三种不同的方式对它就行调用,它产生了三中不同的效果

这样的案例可以给我们什么样的启示呢?

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

image-20241122193140652

1.4 this的绑定规则

  • 绑定规则一:默认绑定;
  • 绑定规则二:隐式绑定;
  • 绑定规则三:显示绑定
  • 绑定规则四:new绑定

1.4.1 规则一:默认绑定

什么情况下使用默认绑定呢?独立函数调用

独立的函数调用我们可以理解成函数没有被绑定到某个对象上进行调用

  //1.定义函数function foo() {console.log("foo:",this)}foo()//默认调用,this指向window//2.函数定义在对象中,但是独立调用var obj = {name:"why",bar:function() {console.log("bar:",this)}}var baz = obj.barbaz()//独立函数调用//3.高阶函数
function test(fn) {fn()
}
test(obj.bar)

严格模式下,独立函数调用的函数中的this指向的是undefined

   "use strict"//1.定义函数function foo() {console.log("foo:",this)}foo()//默认调用,this指向window//2.函数定义在对象中,但是独立调用var obj = {name:"why",bar:function() {console.log("bar:",this)}}var baz = obj.barbaz()//独立函数调用

1.4.2 隐式绑定

另外一种比较常见的调用方式就是通过某个对象进行调用的

  • 也就是它的调用位置中,是通过某个对象发起的函数调用
  //你不知道的JavaScript(上中下)function foo() {console.log("foo函数:",this)}var message = "Hello World"var obj = {bar:foo}obj.bar()

image-20241122195424498

偷偷的把这个this绑定到这个对象上了

1.4.3 new绑定

JavaScript中函数可以当做一个类的构造函数来使用,也就是new关键字

使用new关键字来调用函数时,会执行如下的操作

  1. 创建一个全新的对象
  2. 这个对象会被执行prototype连接
  3. 这个新对象会绑定到函数调用的这个this上(this绑定在这个步骤完成
  4. 如果函数没有返回其他对象,表达式辉返回这个新对象
   /*1. 创建新的空对象2.将this指向这个空对象3.执行函数体中的代码4.没有显示返回这个非空对象时,默认返回这个对象*/function foo() {console.log("foo函数:",this)this.name = "why"}new foo()

image-20241122200405676

1.4.4 this的绑定规则四-显示绑定

隐式绑定有一个前提条件

  • 必须在调用的对象内部有一个对函数的引用(比如一个属性)
  • 如果没有这样的引用,在进行调用时,会报找不到该函数的错误
  • 正是通过这个引用,间接将this绑定到了这个对象上

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

  • JavaScript所有的函数都可以使用call和apply方法

    • 第一个参数是相同的,要求传入一个对象
      • 这个对象的作用是什么呢?就是给this准备的
      • 在调用这个函数时,会将this绑定到这个传入的对象中
    • 后面的参数,apply为数组,call为参数列表

    image-20241122210225518

  • 因为上面的过程,我们明确的绑定了this指定的对象,所以称之为显示绑定

 var obj = {name:"why"}function foo() {console.log("foo函数:",this)}//执行函数,并且函数中的this指向obj这个对象obj.foo = foo//先把这个函数放到obj里面obj.foo()//这个绑定方法比较麻烦,需要在对象里面添加一个属性,然后在把属性赋值给当前对象,在调用,太麻烦了//直接执行函数,并且强制this就是obj对象foo.call(obj)foo.call(123)foo.call("abc")foo.call(undefined)//指向window

image-20241122201603877

 //call/applyfunction foo(name,age,height) {console.log("foo函数被调用:",this)}//()调用foo("why",18,1.88)//window//apply//第一个参数:绑定this//第二个参数:传入额外的实参,以数组的形式foo.apply("apply",["kobe",30,1.98])//String//call//第一个参数:绑定this//参数列表:后续的参数是以我们多参数来传递的,会作为我们的实参foo.call("call","james",25,2,2.05)

image-20241122210020892

如果我们希望this总是绑定到一个对象上,可以怎么做呢?

  • 使用bind方法,bind()方法创建一个新的绑定函数(bound function,BF);

1.4.5 call、apply、bind

  • 通过call或者apply绑定this对象

显示绑定后,this就会明确的指向绑定的对象

function foo() {
console.log(this);
}foo.call(window);//window
foo.call({name:"why"});
foo.call(123); //Number对象,存放时123

如果我们希望一个函数总是显示的绑定到一个对象上,可以怎么做呢

  1. 使用bind方法,bind()方法创建一个新的绑定函数(boud function,BF)
  2. 绑定函数是一个 exotic function object(怪异函数对象,ECMAScript 2015中的术语)
  3. 在bind()被调用时,这个新函数的this被指定为bind()的第一个参数,而其余参数将作为新函数的参数,供调用
  function foo() {console.log("foo:",this)}var obj = {name:"why"}//需求:调用foo时,总是绑定到obj对象身上(不希望obj对象身上有我们的函数)var bar = foo.bind(obj)//其实在执行这行foo.bind(obj)时,生成了一个新的函数,原有的foo函数还是指向window,bar函数指向这个被绑定的对象bar()//this指向的是objbar()
 function foo() {console.log("foo:",this)}var obj = {name:"why"}//需求:调用foo时,总是绑定到obj对象身上(不希望obj对象身上有我们的函数)var bar = foo.bind(obj)//其实在执行这行foo.bind(obj)时,生成了一个新的函数,原有的foo函数还是指向window,bar函数指向这个被绑定的对象bar()//this指向的是objbar()//2.bind函数的其他参数(了解)var bar = foo.bind(obj,"kobe",18,1.88)bar("james")

1.5 内置函数的调用

有些时候,我们辉调用一些JavaScript的内置函数,或者一些第三方库中的内置函数

  • 这些内置函数要求我们传入内外一个函数
  • 我们自己并不会显示的调用这些函数,而且JavaScript内部或者第三方库会帮助我们执行
  • 这些函数中的this是如何绑定的呢?

setTimeout\数组中的forEach、div的点击

    //1.定时器setTimeout(function() {console.log("定时器函数:",this)  //默认指向Window},10000)

自动调用,this指向window

image-20241124181432615

内置函数(第三方库):根据一些经验,Vue传入生命周期函数
 //2.按钮的点击监听var btnE1 = document.querySelector("button")btnE1.onclick = function() {console.log("btn的点击:",this)}btnE1.addEventListener("click:",function(){console.log("btn的点击:",this)})

image-20241124182105226

  //forEachvar names = ["abc","cba","nba"]names.forEach(function(item){console.log("foeEach:",this)})

image-20241124182417693

image-20241124182422186

  //forEachvar names = ["abc","cba","nba"]names.forEach(function(item){console.log("foeEach:",this)},"aaaaaa")  //显示绑定

image-20241124182557559

1.6 this绑定的优先级比较

学了四条规则,接下来开发中我们只需要去查找函数的调用应用了哪条规则即可,但是如果一个函数调用的位置应用了多条规则,优先级谁更高?

  1. 默认规则的优先级是最低的

毫无疑问,默认规则的优先级是最低的,因为存在其他规则时,就会通过其他规则的方式来绑定this

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

代码测试

  1. new绑定的优先级高于隐式绑定

代码测试

  1. new绑定的优先级高于bind
  • new绑定和call、apply是不允许同时使用的,所以不存在谁的优先级更高
  • new绑定可以和bind一起使用,new绑定优先级更高
  • 代码测试

优先级顺序

new
bind
/apply/call
隐式绑定
默认绑定
bind的优先级高于apply

1.7 this规则之外-忽略显示绑定

上述的规则已经足以应付平时的开发,但是总有一些语法,超出了我们的规则之外。(神话故事和动漫中总是有类似这样的人物)

  1. 情况一:如果在显示绑定中,我们传入一个null或者undefined,那么这个显示绑定会被忽略,使用默认规则:
  function foo() {console.log("foo:",this)}foo.apply("abc")foo.apply(null)foo.apply(undefined)

image-20241124200434888

在严格模式下,绑定的使我们基本数据类型,就不是一个对象

  "use strict"function foo() {console.log("foo:",this)}foo.apply("abc")foo.apply(null)foo.apply(undefined)

image-20241124200610556

1.7.1 间接函数的引用

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

  • 赋值(obj2.foo = obj1.foo()的结果是foo函数
  • foo函数被直接调用,那么是默认绑定

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux---ps命令

​​​​​​Linux ps 命令 | 菜鸟教程 (runoob.com) process status 用于显示进程的状态 USER: 用户名,运行此进程的用户名。PID: 进程ID(Process ID),每个进程的唯一标识号%CPU: 进程当前使用的CPU百分比%MEM: 进程当前使用的…

【Spiffo】环境配置:VScode+Windows开发环境

摘要: 在Linux下直接开发有时候不习惯快捷键和操作逻辑,用Windows的话其插件和工具都更齐全、方便,所以配置一个Windows的开发环境能一定程度提升效率。 思路: 自己本地网络内远程连接自己的虚拟机(假定用的是虚拟机…

[ubuntu]编译共享内存读取出现read.c:(.text+0x1a): undefined reference to `shm_open‘问题解决方案

问题log /tmp/ccByifPx.o: In function main: read.c:(.text0x1a): undefined reference to shm_open read.c:(.text0xd9): undefined reference to shm_unlink collect2: error: ld returned 1 exit status 程序代码 #include <stdio.h> #include <stdlib.h> #…

Java基于Spring Boot框架的房屋租赁系统,附源码

博主介绍&#xff1a;✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…

librdns一个开源DNS解析库

原文地址&#xff1a;librdns一个开源DNS解析库 – 无敌牛 欢迎参观我的个人博客&#xff1a;无敌牛 – 技术/著作/典籍/分享等 介绍 librdns是一个开源的异步多功能插件式的解析器&#xff0c;用于DNS解析。 源代码地址&#xff1a;GitHub - vstakhov/librdns: Asynchrono…

CTFHUB--yeeclass-web

复现平台CTFHUB靶机为一个完整类论坛网页&#xff0c;题目给了服务端完整代码 代码审计 /src/submit.php Line56-63: 可以看到提交数据存入的时候将$_SESSION["username"]."_"作为前缀&#xff0c;生成了一个uniqid。uniqid的生成方式即{sec:08x}{usec:0…

DataWhale—PumpkinBook(TASK05决策树)

课程开源地址及相关视频链接&#xff1a;&#xff08;当然这里也希望大家支持一下正版西瓜书和南瓜书图书&#xff0c;支持文睿、秦州等等致力于开源生态建设的大佬✿✿ヽ(▽)ノ✿&#xff09; Datawhale-学用 AI,从此开始 【吃瓜教程】《机器学习公式详解》&#xff08;南瓜…

计算机网络socket编程(2)_UDP网络编程实现网络字典

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 计算机网络socket编程(2)_UDP网络编程实现网络字典 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记&#xff0c;欢迎大家在评论区交流讨…

51c多模态~合集3

我自己的原文哦~ https://blog.51cto.com/whaosoft/12409223 #TextHarmony 字节联合华师提出统一的多模态文字理解与生成大模型 字节跳动与华东师范大学联合提出的TextHarmony模型&#xff0c;这是一个统一的多模态文字理解与生成大模型&#xff0c;它通过创新的Slide-LoRA…

el-table vue3统计计算数字

固定合计在最下列 父组件 <template><el-tablev-loading"loading"tooltip-effect"light":data"list"style"width: 100%":max-height"maxHeight"element-loading-text"拼命加载中...":header-cell-styl…

【大数据学习 | Spark-Core】详解分区个数

RDD默认带有分区的&#xff0c;那么创建完毕rdd以后他的分区数量是多少&#xff1f; 从hdfs读取文件的方式是最正规的方式&#xff0c;我们通过计算原理可以推出blk的个数和分区数量是一致的&#xff0c;本地化计算。 我们可以发现数据的读取使用的是textInputFormat&#xff…

Mysql的加锁情况详解

最近在复习mysql的知识点&#xff0c;像索引、优化、主从复制这些很容易就激活了脑海里尘封的知识&#xff0c;但是在mysql锁的这一块真的是忘的一干二净&#xff0c;一点映像都没有&#xff0c;感觉也有点太难理解了&#xff0c;但是还是想把这块给啃下来&#xff0c;于是想通…

Java基础-Java多线程机制

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 一、引言 二、多线程的基本概念 1. 线程与进程 2. 多线程与并发 3. 多线程的优势 三、Java多线程的实…

【LeetCode面试150】——202快乐数

博客昵称&#xff1a;沈小农学编程 作者简介&#xff1a;一名在读硕士&#xff0c;定期更新相关算法面试题&#xff0c;欢迎关注小弟&#xff01; PS&#xff1a;哈喽&#xff01;各位CSDN的uu们&#xff0c;我是你的小弟沈小农&#xff0c;希望我的文章能帮助到你。欢迎大家在…

详细教程-Linux上安装单机版的Hadoop

1、上传Hadoop安装包至linux并解压 tar -zxvf hadoop-2.6.0-cdh5.15.2.tar.gz 安装包&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1u59OLTJctKmm9YVWr_F-Cg 提取码&#xff1a;0pfj 2、配置免密码登录 生成秘钥&#xff1a; ssh-keygen -t rsa -P 将秘钥写入认…

Python 获取微博用户信息及作品(完整版)

在当今的社交媒体时代&#xff0c;微博作为一个热门的社交平台&#xff0c;蕴含着海量的用户信息和丰富多样的内容。今天&#xff0c;我将带大家深入了解一段 Python 代码&#xff0c;它能够帮助我们获取微博用户的基本信息以及下载其微博中的相关素材&#xff0c;比如图片等。…

07-SpringCloud-Gateway新一代网关

一、概述 1、Gateway介绍 官网&#xff1a;https://spring.io/projects/spring-cloud-gateway Spring Cloud Gateway组件的核心是一系列的过滤器&#xff0c;通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前沿的防…

MyBatis基本使用

一、向SQL语句传参: 1.MyBatis日志输出配置: mybatis配置文件设计标签和顶层结构如下: 可以在mybatis的配置文件使用settings标签设置&#xff0c;输出运过程SQL日志,通过查看日志&#xff0c;可以判定#{}和${}的输出效果 settings设置项: logImpl指定 MyBatis 所用日志的具…

实验二 系统响应及系统稳定性

实验目的 &#xff08;1&#xff09;学会运用Matlab 求解离散时间系统的零状态响应&#xff1b; &#xff08;2&#xff09;学会运用Matlab 求解离散时间系统的单位取样响应&#xff1b; &#xff08;3&#xff09;学会运用Matlab 求解离散时间系统的卷积和。 实验原理及实…

秋招面试基础总结,Java八股文基础(串联知识),四万字大全

目录 值传递和引用传递 静态变量和静态代码块的执行顺序 Java​​​​​​​集合的框架&#xff0c;Set,HashSet,LinkedHashSet这三个底层是什么 多线程篇 Java实现多线程的方式 假设一个线程池&#xff0c;核心线程数是2&#xff0c;最大线程数是3&#xff0c;阻塞队列是4…