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

embedded/2024/11/25 8:58:31/

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.ppmy.cn/embedded/140348.html

相关文章

Puppeteer 和 Cheerio 在 Node.js 中的应用

Puppeteer 和 Cheerio 在 Node.js 中的应用 引言 在现代 Web 开发中,自动化测试、数据抓取和页面分析是常见的需求。Node.js 提供了丰富的工具和库来满足这些需求。本文将介绍两个在 Node.js 中常用的库:Puppeteer 和 Cheerio,它们分别用于…

学习ASP.NET Core的身份认证(基于Cookie的身份认证2)

采用基于Cookie的身份认证,在调用services.AddAuthentication注册服务时,可以通过CookieAuthenticationOptions对象按需设置Cookie属性,常用的包括以下属性(更详细的介绍见参考文献2,微软的帮助文档中的介绍看的头大&a…

【PHP】 环境以及插件的配置,自学笔记(一)

文章目录 环境的准备安装 XAMPPWindowMacOS 配置开发环境Vscode 关于 PHP 的插件推荐Vscode 配置 php 环境Apache 启动Hello php配置热更新 参考 环境的准备 下载 XAMPP , 可以从 官网下载 https://www.apachefriends.org/download.html 安装 XAMPP XAMPP 是一个跨平台的集成开…

jquery还有其应用场景,智慧慢慢地被边缘化,但不会消亡

一、jQuery 的辉煌过往 jQuery 的诞生与崛起 在前端开发的漫长历史中,2006 年诞生的 jQuery 犹如一颗耀眼的新星划破天际。它由 John Resig 创造,一出现便以其独特的魅力迅速吸引了广大开发者的目光。在那个前端技术发展相对缓慢的时期,jQue…

CTF之密码学(培根密码)

培根密码,又名倍康尼密码(Bacons cipher),是由法兰西斯培根发明的一种隐写术,属于密码学领域的一种替换密码。以下是关于培根密码的详细介绍: 一、原理 培根密码本质上是一种二进制密码,但它没…

大宗商品行业区块链应用

应用场景 区块链技术具有透明性、去中心化、不可篡改等特点,因此可以在大宗商品定价方面得到应用。通过区块链技术,相关交易的各方可以在无需依赖中心化第三方的情况下,实时、准确地获取定价信息。这种技术的应用能够提高效率、降低成本、提…

枫清科技亮相 2024 中国 5G+工业互联网大会,推动 AI 赋能新型工业化

11 月 19 日,2024 中国 5G工业互联网大会在武汉盛大开幕,吸引了来自国内外的行业专家与领先企业。本次大会以“实数融合 智造翘楚”为主题,重点围绕 5G 与工业互联网的深度融合应用、人工智能、智能网联汽车等领域展开讨论与成果展示。作为行…

[OpenHarmony5.0][Docker][环境]OpenHarmony5.0 Docker编译环境镜像下载以及使用方式

0. 制作过程 如果你想知道这个镜像是如何制作的,请看下面的教程,如果你只想拿到镜像。那就往下看就好了 链接: 1. 获取源码 源码下载请参考:OHOS_5.0中的[源码下载]章节,建议使用镜像站点下载。 2. 获取镜像 云盘上…