前端学习<四>JavaScript基础——25-this指向

执行期上下文

函数执行时(准确来说,是在函数发生预编译的前一刻),会创建一个执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境。

每调用一次函数,就会创建一个新的上下文对象,他们之间是相互独立且独一无二的。当函数执行完毕,它所产生的执行期上下文会被销毁。

参考链接:https://www.cnblogs.com/chenyingjie1207/p/9966036.html

this 指向

解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是 this,this 指向的是一个对象,这个对象我们称为函数执行的 上下文对象。

ES5 函数内 this 的指向【非常重要】

我们在《JavaScript 基础/函数.md》这篇文章讲过,函数的调用有六种形式。

在ES5语法中,根据函数的调用方式的不同,this 会指向不同的对象:

1、以函数的形式(包括普通函数、定时器函数、立即执行函数)调用时,this 的指向永远都是 window。比如fun();相当于window.fun();

2、以方法的形式调用时,this 指向调用方法的那个对象

3、以构造函数的形式调用时,this 指向实例对象

4、以事件绑定函数的形式调用时,this 指向绑定事件的对象

5、使用 call 和 apply 调用时,this 指向指定的那个对象

第 1 条的举例

 function fun() {console.log(this);console.log(this.name);}​var obj1 = {name: 'smyh',sayName: fun,};​var obj2 = {name: 'vae',sayName: fun,};​var name = '全局的name属性';​//以函数形式调用,this是windowfun(); //可以理解成 window.fun()

打印结果:

     Window全局的name属性

上面的举例可以看出,this 指向的是 window 对象,所以 this.name 指的是全局的 name。

第 2 条的举例

 function fun() {console.log(this);console.log(this.name);}​var obj1 = {name: 'smyh',sayName: fun,};​var obj2 = {name: 'vae',sayName: fun,};​var name = '全局的name属性';​//以方法的形式调用,this是调用方法的对象obj2.sayName();

打印结果:

     Objectvae

上面的举例可以看出,this 指向的是 对象 obj2 ,所以 this.name 指的是 obj2.name。

ES6 箭头函数中 this 的指向

ES6 中的箭头函数并不使用上面的准则,而是会继承外层函数调用的 this 绑定(无论 this 绑定到什么)。

改变函数内部的 this 指向

JS 专门为我们提供了一些方法来改变函数内部的 this 指向。常见的方法有 call()、apply()、bind() 方法。继续往下看。

call()

call() 方法的作用

call() 方法的作用:可以调用一个函数,与此同时,它还可以改变这个函数内部的 this 指向。

call() 方法的另一个应用:可以实现继承。之所以能实现继承,其实是利用了上面的作用。

语法:

 fn1.call(想要将this指向哪里, 函数实参1, 函数实参2);

备注:第一个参数中,如果不需要改变 this 指向,则传 null。

call() 方法举例

举例 1、通过 call() 调用函数:

 const obj1 = {nickName: 'qianguyihao',age: 28,};function fn1() {console.log(this);console.log(this.nickName);}fn1.call(this); // this的指向并没有被改变,此时相当于 fn1();

上方代码的打印结果:

 windowundefined

上面的代码,跟普通的函数调用 fn1() 没有区别。

举例 2、通过 call() 改变 this 指向:

 var obj1 = {nickName: 'qianguyihao',age: 28,};​function fn1(a, b) {console.log(this);console.log(this.nickName);console.log(a + b);}​fn1.call(obj1, 2, 4); // 先将 this 指向 obj1,然后执行 fn1() 函数

上方代码的打印结果:

obj1
qianguyihao
6

举例 3、通过 call() 实现继承:

// 给 Father 增加 name 和 age 属性
function Father(myName, myAge) {this.name = myName;this.age = myAge;
}function Son(myName, myAge) {// 【下面这一行,重要代码】// 通过这一步,将 father 里面的 this 修改为 Son 里面的 this;另外,给 Son 加上相应的参数,让 Son 自动拥有 Father 里的属性。最终实现继承Father.call(this, myName, myAge);
}const son1 = new Son('千古壹号', 28);
console.log(JSON.stringify(son1));

上方代码中,通过 call() 方法,让 Son 继承了 Father 里面的 name 和 age 属性。

打印结果:

{"myName":"千古壹号","myAge":28}

apply() 方法

apply() 方法的作用

apply() 方法的作用:可以调用一个函数,与此同时,它还可以改变这个函数内部的 this 指向。这一点,和 call()类似。

apply() 方法的应用: 由于 apply()需要传递数组,所以它有一些巧妙应用,稍后看接下来的应用举例就知道了。

语法:

fn1.apply(想要将this指向哪里, [函数实参1, 函数实参2]);

备注:第一个参数中,如果不需要改变 this 指向,则传 null。

到这里可以看出, call() 和 apply() 方法的作用是相同的。唯一的区别在于,apply() 里面传入的实参,必须是数组(或者伪数组)

apply() 方法举例

举例、通过 apply() 改变 this 指向:

var obj1 = {nickName: 'qianguyihao',age: 28,
};function fn1(a) {console.log(this);console.log(this.nickName);console.log(a);
}fn1.apply(obj1, ['hello']); // 先将 this 指向 obj1,然后执行 fn1() 函数

注意,上方代码中,apply() 里面传实参时,需要以数组的形式。即便是传一个实参,也需要传数组。

打印结果:

obj1
qianguyihao
hello

apply() 方法的巧妙应用:求数组的最大值

我们知道,如果想要求数组中元素的最大值,数组本身是没有自带方法的。那怎么办呢?

虽然数组里没有获取最大值的方法,但是数值里有 Math.max(数字1,数字2,数字3) 方法,可以获取多个数值中的最大值。 另外,由于 apply() 方法在传递实参时,传的刚好是数组,所以我们可以 通过 Math.max() 和 apply() 曲线救国。

举例:求数组中多个元素的最大值:

const arr1 = [3, 7, 10, 8];// 下面这一行代码的目的,无需改变 this 指向,所以:第一个参数填 null,或者填 Math,或者填 this 都可以。严格模式中,不让填null。
const maxValue = Math.max.apply(Math, arr1); // 求数组 arr1 中元素的最大值
console.log(maxValue);const minValue = Math.min.apply(Math, arr1); // 求数组 arr1 中元素的最小值
console.log(minValue);

打印结果:

10
3

bind() 方法

bind() 方法的作用

bind() 方法不会调用函数,但是可以改变函数内部的 this 指向。

把call()、apply()、bind()这三个方法做一下对比,你会发现:实际开发中, bind() 方法使用得最为频繁。如果有些函数,我们不需要立即调用,但是又想改变这个函数内部的this指向,此时用 bind() 是最为合适的。

语法:

新函数 = fn1.bind(想要将this指向哪里, 函数实参1, 函数实参2);

参数:

  • 第一个参数:在 fn1 函数运行时,指定 fn1 函数的this 指向。如果不需要改变 this 指向,则传 null。

  • 其他参数:fn1 函数的实参。

解释:它不会调用 fn1 函数,但会返回 由指定this 和指定实参的原函数拷贝。可以看出, bind() 方法是有返回值的。

赞赏作者

创作不易,你的赞赏和认可,是我更新的最大动力:

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

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

相关文章

git 分支-变基

在git中,将一个分支的更改集成到另一个分支有两种主要方式:合并(merge)和变基(rebase)。在本节中,将学习什么是变基,如何执行变基操作,为什么它是一个非常强大的工具&…

【题目】【信息安全管理与评估】2022年国赛高职组“信息安全管理与评估”赛项样题9

【题目】【信息安全管理与评估】2022年国赛高职组“信息安全管理与评估”赛项样题9 信息安全管理与评估 网络系统管理 网络搭建与应用 云计算 软件测试 移动应用开发 任务书,赛题,解析等资料,知识点培训服务 添加博主wx:liuliu548…

网工交换基础——MUX VLAN

前言: MUX VLAN(Multiplex VLAN,多复用VLAN)提供了一种通过VLAN进行网络资源控制的机制。例如,在企业网络中,企业员工和企业客户可以访问企业的服务器。对于企业来说,希望企业内部员工之…

Docker安装(一)

一、安装Docker 服务器系统:centos 7 1.本地有docker的首先卸载本机docker yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-selinux \docker-engine-selinux \dock…

算法训练营第43天|LeetCode 1049.最后一块石头的重量Ⅱ 494.目标和 474.一和零

LeetCode 1049.最后一块石头的重量Ⅱ 题目链接&#xff1a; LeetCode 1049.最后一块石头的重量Ⅱ 代码&#xff1a; class Solution { public:int lastStoneWeightII(vector<int>& stones) {int sum 0;int size stones.size();for(int i0;i<size;i){sum st…

整合Mybatis,配置数据库

整合mybatis需要加入起步依赖&#xff1a; <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.0</version> </dependency>引入这个依赖就相当…

RHCE在系统设定延迟任务与定时任务

实验定义 延迟任务和定时任务都是常见的任务调度机制&#xff0c;用于在特定时间点或时间间隔触发执行任务。它们在系统开发中经常被使用。 延迟任务 延迟任务是指在一定的时间间隔之后执行的任务。我们可以指定一个时间延迟&#xff0c;然后在延迟时间过后执行相应的任务。…

软企必备CMMI | 哪些企业可以认证?一文讲解CMMI认证条件周期以及好处!

CMMI&#xff0c;即能力成熟度模型集成&#xff0c;是由美国软件工程研究所制定的一种评价软件企业能力成熟度和过程改进的国际标准。随后在世界形成推广的一种软件评估标准&#xff0c;对企业的软件综合管理形成一套体系建立&#xff0c;用于改善软件质量的方法。 CMMI认证旨…

selenum操作cookie进行免登陆【爬虫必修课1】

Selenium 操作 Cookie 进行免登录 使用 Selenium 自动化登录网站是一个常见的需求。但是直接输入用户名和密码登录非常不安全,同时每次登录都需要重复这个操作也很麻烦。一个更好的方式是使用 Cookie 进行免登录。 这篇博客就来介绍如何使用 Selenium 实现 Instagram 的免登录…

计算机知识介绍,本地MAC地址是什么

MAC地址&#xff0c;全称媒体访问控制地址&#xff08;Media Access Control Address&#xff09;&#xff0c;也称为物理地址或硬件地址。它是网络设备&#xff08;例如网卡、无线网卡&#xff09;的唯一标识符。 MAC地址由48位&#xff08;6个字节&#xff09;二进制数组成&…

Vue3从入门到实战:深度掌握组件通信(下部曲)

5.组件通信方式5-$attrs $attrs的概念&#xff1a; 在Vue中&#xff0c;$attrs 是一个特殊的属性&#xff0c;用于访问父组件向子组件传递的非特定属性。它可以让子组件轻松地获取父组件传递的属性&#xff0c;而无需在子组件中显式声明这些属性。 想象一下你有一个父组件和…

Connection: keep-alive 2

一、请求保持多久后关闭 客户端主动关闭连接&#xff1a;当客户端不再发送请求&#xff0c;并且已经接收到服务器的完整响应后&#xff0c;客户端可以选择关闭连接。这通常发生在客户端已经获取到所需资源后&#xff0c;或者在客户端程序执行完毕后。 服务器主动关闭连接&…

C++进阶(2)-函数

目录 一、函数提高 1.1函数默认参数 1.2函数占位参数 1.3函数重载 1.3.1函数重载概述 1.3.2函数重载注意事项 二、类和对象 2.1封装 2.1.1封装的意义 2.1.2struct和class区别 2.1.3成员属性设置为私有 2.1.4封装案例 2.2对象的初始化和清理 2.2.1构造函数和析构函数 …

【设计模式之美】快速地改善代码质量的几条编程规范(上)

文章目录 一. 命名二. 关于注释三. 代码风格 超实用的改善代码质量的编程规范 一. 命名 关于命名命名的关键是能准确达意。作用域小的变量&#xff08;比如临时变量&#xff09;&#xff0c;可以适当地选择短一些的命名方式。我们可以借助类的信息来简化属性、函数的命名&#…

科技强国路上的创新先行者,以科技创新筑梦未来

随着我国创新驱动发展战略的深入实施&#xff0c;国家科技实力显著增强&#xff0c;正逐步迈向“科技强国”。在今年3月&#xff0c;全国“两会”的政府工作报告中&#xff0c;强调了国家为“科技创新”推出的多项有力举措&#xff0c;同时&#xff0c;“新质生产力”、“人工智…

eNSP防火墙配置实验(trust、DMZ、untrust)

【拓扑】 设备 接口 IP地址/子网掩码/网关 AR1 G0/0/0 10.1.3.2/24 G0/0/1 100.1.1.2/24 FW1 G0/0/0 192.168.166.254/24 G1/0/0 10.1.1.1/24&#xff0c;trust域 G1/0/1 10.1.2.1/24&#xff0c;DMZ域 G1/0/2 100.1.3.1/24&#xff0c;untrust域 LSW1 G0/0/…

大孔树脂与凝胶型树脂的区别及应用

在工业和环境工程中&#xff0c;离子交换树脂被广泛用于处理水和废水&#xff0c;去除有害的化学物质。两种常见的离子交换树脂类型是大孔树脂和凝胶型树脂。尽管它们在功能上有所重叠&#xff0c;但在物理结构、性能和应用领域上存在显著差异。本文将探讨这两种树脂的特点、区…

微服务组件-注册中心

微服务组件-注册中心 使用restTemplate实现远程服务调用存在以下的问题&#xff1a; 1、消费者不知道如何获取服务提供者具体信息。 2、在远程调用的过程中&#xff0c;直接采用填写url的硬编码方式&#xff0c;如果服务消费者发生变化&#xff0c;得到的结果就会出错。 3、如果…

vue+element作用域插槽

作用域插槽的样式由父组件决定&#xff0c;内容却由子组件控制。 在el-table使用作用域插槽 <el-table><el-table-column slot-scope" { row, column, $index }"></el-table-column> </el-table>在el-tree使用作用域插槽 <el-tree>…

基于SpringBoot+Vue的二手车交易系统的设计与实现(源码+文档+包运行)

一.系统概述 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统二手车交易信息管理难度大&#xff0c;容错率低&…