JavaScript高架高级(四)---这可能是你看过的最完整的this指向

 前言

简单阐述

  • 前端的初学者在学习Javascript中this指向的时候经常都会一头雾水,尤其是在ES6箭头函数出现之前。

  • this指向之所以容易让人头疼,原因在于 this 是在代码执行时根据环境和情况不同才决定绑定为什么值。

  • 所以本篇文章主要是介绍和总结了各种情况下的this指向,如果文中有写的不对的地方或者明显错误,还请不吝指出互相交流。如果对你有帮助,也请不要吝啬手中的点赞~谢谢

在开始之前,还是需要介绍this的一些基础知识,具体如下:

  1. this 是javascript中的一个关键字,并非是一个变量。
  2. this 关键字指向的是一个对象,而指向哪个对象,或者是这个对象的值是什么取决于使用(调用)的方式和环境。
  3. this 指向的值是可以通过手动方式去改变的,比如call、bind、apply方法。
  4. this 在严格模式和非严格模式下也会有差别。

this的作用

  • 从某些角度来说,开发中我们没有this,也是有解决方案的,但是如果真的没有this,会让我们编写代码十分不方便。
  • 例如:
         // 如果没有this,我们更改了obj的命名 // 那么下面的obj.name 都需要进行修改var obj = {var name = "malong"eating: function() {console.log(obj.name + "吃东西")}studying: function() {console.log(obj.name + "学习")}}

    this的指向

  • 在多数情况下,this出现在函数中,正常开发,通常都是在函数中使用this
    • 所有的函数在被调用时,都会创建一个执行上下文FEC
    • 这个上下文中记录着函数的调用栈、AO对象等;
    • this也是其中的一条记录;
  • 函数在调用时,JavaScript会默认给this绑定一个值
  • this的绑定和定义的位置(编写的位置)没有关系
  • this的绑定和调用方式以及调用的位置有关系

this绑定方式1:默认绑定

独立的函数调用我们可以理解成函数没有被绑定到某个对象上进行调用,这样this就是默认绑定

this是在运行时被绑定的

// 案例1 默认绑定
function foo() {console.log(this)
}// 案例2 默认绑定
function test1() {console.log(this)test2()
}function test2() {console.log(this)test3()
}function test3() {console.log(this)
} 
test1()// 案例3 默认绑定
function bar() {func()
}var obj = {name: "malong",foo: function() {console.log(this)}
}bar(obj.foo)

this绑定方式2:隐式绑定

  • 必须在调用的对象内部有一个对函数的引用(比如一个属性)
  • 如果没有这样的引用,在进行调用时,会报找不到该函数的错误
  • 正是通过这个引用,间接的将this绑定到了这个对象上
  • 调用方式是通过某个对象进行调用的,隐式绑定
// 案例1 隐式绑定
function foo() {console.log(this)
}var obj = {name: "malong",foo: foo
}obj.foo()// 案例2 隐式绑定
function bar() {console.log(this)
}var obj1 = {name: "malong1",bar: bar
}var obj2 = {name: "malong2",obj1: obj1
}obj2.obj1.bar()// 案例3 隐式绑定
function baz() {console.log(this)
}var obj3 = {name: "malong",foo: baz
}var fn = obj3.foo;
fn()

this绑定方式3:显示绑定

  • bind
    • 形参第一个参数是对象,第二个参数是列表,返回值是一个函数。
  • call
    • 形参第一个参数是对象,第二个参数是列表
  • apply
  • 形参第一个参数是对象,第二个参数是数组 通过call绑定this
        function foo() {console.log(this)}foo.call(window)foo.call({name: "malong"})foo.call(123)
    

    如果我们希望一个函数总是显示绑定到一个对象上,而不用向上面那样写多次:

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

    this绑定方式4:new绑定

  • JavaScript中的函数可以当做一个类的构造函数来使用,也就是使用new关键字。
    function Person(name) {console.log(this)this.name = name
    }var person = new Person("malong")
    

    this的绑定过程:

  • 创建一个新的对象
  • 将构造函数的作用域赋值给新对象(构造函数.prototype === 对象.__ proto__)
  • 执行构造函数中的代码(this绑定在这个步骤完成)
  • 返回这个对象(内部有一个隐式的 return this)

this绑定优先级

new > 显示绑定(apply,call,bind) > 隐式绑定 > 默认

扩展【一】:this规则之外

无视显示绑定规则:

function foo() {console.log(this)
}var obj = {name: "malong"
}foo.call(obj)
foo.call(null)
foo.call(undefined)var baz = foo.bind(null)
baz()

间接函数引用:

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

箭头函数:

  • 箭头函数没有this,它的this由运行时外层作用域的this决定
  • 箭头函数没有arguments
  • 箭头函数不能new
  • var name = "window";var obj = {name: "obj",getData: function() {// 会默认绑定,所以这里的this是 objsetTimeout(() => {console.log(this)}, 100)}}// 如果getData也是一个箭头函数,那么this会是windowobj.getData()

    扩展【二】:this面试题

  •     var name = "window"var person = {name: "person",sayName: function() {console.log(this.name);}};function sayName() {var sss = person.sayName;sss();person.sayName();(person.sayName)();(b = person.sayName)();}sayName()
    
        var name = "window";var person1 = {name: "person1",foo1: function () {console.log(this.name)},foo2: () => console.log(this.name),foo3: function () {return function () {console.log(this.name)}},foo4: function () {return () => {console.log(this.name)}}}var person2 = { name: "person2" }person1.foo1();person1.foo1.call(person2);person1.foo2();person1.foo2.call(person2)person1.foo3()()person1.foo3.call(person2)()person1.foo3().call(person2)person1.foo4()()person1.foo4.call(person2)()person1.foo4().call(person2)
    
     var name = 'window'function Person(name) {this.name = name;this.obj = {name: 'obj',foo1: function () {return function () {console.log(this.name)}},foo2: function () {return () => {console.log(this.name)}}}}var person1 = new Person('person1')var person2 = new Person('person2')person1.obj.foo1()()person1.obj.foo1.call(person2)()person1.obj.foo1().call(person2)person1.obj.foo2()()person1.obj.foo2.call(person2)()person1.obj.foo2().call(person2)
    

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

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

相关文章

Openstack(T) 部署Ceilometer服务 ---mongo命令error

执行如下命令 # mongo --host controller --eval db db.getSiblingDB("ceilometer"); db.addUser({user: "ceilometer", pwd: "admin123", roles: [ "readWrite", "dbAdmin" ]}) 出现错误 1.安装mongo ①vi /etc/yum.r…

数据结构进阶篇 之 【二叉树】详细概念讲解(带你认识何为二叉树及其性质)

有朋自远方来,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,鞭数十,驱之别院 一、二叉树 1、二叉树的概念 1.1 二叉树中组分构成名词概念 1.2 二叉树的结构概念 1.3 特殊的二叉树 2、二叉树的存储结构 …

全面:vue.config.js 的完整配置

vue.config.js是Vue项目的配置文件,用于配置项目的构建、打包和开发环境等。 在Vue CLI 3.0之后,项目的配置文件从原来的build和config目录下的多个配置文件,合并成了一个vue.config.js文件。这个文件可以放在项目的根目录下,用于…

向赵丽颖学习大女主式的生活方式!

最近,随着电视剧《与凤行》的热播,赵丽颖再次以其精湛的演技和不变的专业状态回到了大众视野。从《楚乔传》的坚韧女将到《知否知否应是绿肥红瘦》中的睿智女性,赵丽颖的每一次转变都让人眼前一亮。尽管在这几年中,她也经历了许多…

AI入侵游戏业:是颠覆者还是创新助手?揭秘未来游戏新趋势!

在科技日新月异的今天,人工智能(AI)已经成为各行各业的关注焦点。而在娱乐产业中,AI技术的引入也让人们对电子游戏的未来发展产生了无限遐想。那么,AI究竟会给电子游戏行业带来怎样的变革?它会成为行业的颠…

机器学习 - save和load训练好的模型

如果已经训练好了一个模型,你就可以save和load这模型。 For saving and loading models in PyTorch, there are three main methods you should be aware of. PyTorch methodWhat does it do?torch.saveSaves a serialized object to disk using Python’s pickl…

AI大模型学习的伦理与社会影响

AI大模型学习 随着人工智能技术的快速发展,AI大模型学习成为当前热门研究领域之一。AI大模型学习是指基于大规模数据集和深度学习模型进行训练,以实现更高的准确性和复杂性。这些大模型已经在几乎所有领域都取得了显著的成就,包括自然语言处…

通讯录管理系统实现(C++版本)

1.菜单栏的设置 (1)我么自定义了一个showmenu函数,用来打印输出我们的菜单栏; (2)菜单栏里面设置一些我们的通讯录里面需要用到的功能,例如增加联系人,删除联系人等等 2.退出功能…

ocrclass.h:117:18: error: field ‘end_time‘ has incomplete type ‘timeval‘

Alpine Linux v3.5上安装 tesseract-4.1.1 报错: 缺少timeval函数 ocrclass.h:117:18: error: field end_time has incomplete type timeval Current Behavior: In file included from control.cpp:37:0: ../../src/ccutil/ocrclass.h:117:18: error: field end…

javaWeb私人牙科诊所管理系统

一、摘要 随着科技的飞速发展,计算机已经广泛的应用于各个领域之中。在医学领域中,计算机主要应用于两个方面:一是医疗设备智能化,以硬件为主。另一种是病例信息管理系统(HIS)以软件建设为主,以…

1978-2022年全国31省社会消费品零售总额数据

1978-2022年全国31省社会消费品零售总额数据 1、时间:1978-2022年 2、指标:社会消费品零售总额 3、范围:31省市 4、来源:整理自国家统计J和各省年鉴 5、缺失情况说明:1997-2022年31省市均无缺失, 199…

GB 16807-2009 防火膨胀密封件检测

防火膨胀密封件是指火灾时遇火或高温作用能够膨胀,且能辅助建筑构配件使之具有隔火、隔烟、隔热等防火密封性能的产品。 GB 16807-2009防火膨胀密封件检测项目: 测试项目 测试方法 外观 GB 16807 尺寸允许偏差 GB 16807 膨胀性能 GB 16807 产烟…

随机链表的深拷贝

目录 一、何为深拷贝? 二、题目 三、思路 1.拷贝节点插入到原节点后面 2.控制拷贝节点的random 3.脱离原链表 : 尾插的思想 四、代码 五、附加 一、何为深拷贝? 一个引用对象一般来说由两个部分组成:一个具名的Handle,也就…

spring boot3 解决跨域几种方式

在Spring Boot 3中,解决跨域请求(CORS,Cross-Origin Resource Sharing)的问题主要有以下几种方式: 1. 使用CrossOrigin注解 你可以直接在Controller类或者具体的请求处理方法上使用CrossOrigin注解来允许跨域请求。 …

Java面试题:请解释Java中的输入输出(I/O)流?详细说明应用场景

Java中的输入输出(I/O)流是用于读取和写入数据的机制。在Java中,I/O流被设计为按照流的方向和数据源/目标类型进行分类。流的方向分为输入流和输出流,而数据源/目标类型则分为字节流和字符流。 流的方向: 输入流&…

面试官问我 ,try catch 应该在 for 循环里面还是外面?

首先 , 话说在前头, 没有什么 在里面 好 和在外面好 或者 不好的 一说。 本篇文章内容: 使用场景 性能分析 个人看法 1. 使用场景 为什么要把 使用场景 摆在第一个 ? 因为本身try catch 放在 for循环 外面 和里面 &#…

图片标注编辑平台搭建系列教程(2)——fabric.js简介

文章目录 综述数据管理图形渲染图形编辑事件监听预告 综述 fabric提供了二维图形编辑需要的所有基础能力,包括:数据管理、图形渲染、图形编辑和事件监听。其中,图形编辑可以通过事件监听和图形渲染来实现,所以可以弃用。数据管理…

2024年NOC大赛软件创意编程(python初中组初赛)真题

题型和分值:单选题(20题,40分)、判断题(5题,10分)、多选题(5题,20分)、填空题(10题,30分) 一、单选题(每题2分,共20题,满分40分) 1、下面的程序,会无限循环下去的是( ) A&#x…

【数据结构】双向奔赴的爱恋 --- 双向链表

关注小庄 顿顿解馋๑ᵒᯅᵒ๑ 引言:上回我们讲解了单链表(单向不循环不带头链表),我们可以发现他是存在一定缺陷的,比如尾删的时候需要遍历一遍链表,这会大大降低我们的性能,再比如对于链表中的一个结点我们是无法直接…

OJ :1092 :素数表(函数专题)

题目描述 输入两个正整数m和n,输出m和n之间的所有素数。 要求程序定义一个prime()函数和一个main()函数,prime()函数判断一个整数n是否是素数,其余功能在main()函数中实现。 int prime(int n) { //判断n是否为素数, 若n为素数…