当前位置: 首页 > news >正文

说一下this,实现apply、call

理解this

在ES5中,this的指向始终坚持一个原理:“this永远指向最后调用它的那个对象”,切记这句话。下面看几个例子。

例一

var obj = {name: 'zhangsan',say: function() {console.log(this.name);}
}obj.say() // zhangsan 

最基本的使用,函数say是obj调用的,函数中的this指向obj,所以打印的是zhangsan

例二

var name = 'lisi'
var obj = {name: 'zhangsan',say: function() {console.log(this.name);}
}var func = obj.say
func() // lisi 

把say赋给变量func,然后调用func,前面没有调用对象,那么此时的调用对象就是全局对象window,因此this指向window,所以打印lisi

例三

var name = 'lisi'
var obj = {name: 'zhangsan',say: function() {console.log(this.name);}
}window.obj.say() // zhangsan 

this永远指向最后调用它的那个对象,这里虽然前面加了个window,但是最后调用者还是obj,因此this指向obj。

可以看出:this的指向并不是在创建的时候就可以确定的。在ES5中,this永远指向最后调用它的那个对象

例四

var name = 'lisi'var obj = {name: 'zhangsan',say: function() {console.log(this.name); // zhangsanfunc()function func() {console.log(this.name); // lisi}},}obj.say() 

say的调用者是obj,say函数内部的this就指向obj,因此第一次打印zhangsan。再调用func,此时func的调用者是window,func函数内部的this就指向window,因此第二次打印lisi

如何改变this指向

改变this指向有以下几种方法:

  • 使用ES6的箭头函数
  • 把this存一下然后调用:_this=this
  • 使用apply、call、bind改变this指向

箭头函数

ES6中的箭头函数可以避免ES5中很多this的坑。箭头函数中的this始终指向函数定义时的this,而非执行时。箭头函数中没有this绑定,必须通过查找作用域链来决定其值。如果箭头函数被非箭头函数包含,则this绑定的是最近一次非箭头函数的this

例五

var name = 'lisi'var obj = {name: 'zhangsan',func1: function() {console.log(this.name);},func2: function() {setTimeout(function() {this.func1()}, 1000)}
}obj.func2() // this.func1 is not a function 

如上代码,调用func2报错,因为最终调用setTimeout的对象是window,函数里的this指向window,而window中并没有func1,所以报错。

这里补充个知识点:匿名函数的this永远指向window。this永远指向最后调用它的那个对象。我们来找找最后调用匿名函数的对象是哪个,很尴尬,匿名函数没有名字,所以是没有办法被其他对象调用的,所以只能在window下执行。因此匿名函数的this始终指向window。

var name = 'lisi'var obj = {name: 'zhangsan',func1: function() {console.log(this.name);},func2: function() {// 使用箭头函数setTimeout(() => {this.func1()}, 1000)}
}obj.func2() // zhangsan 

使用箭头函数即可解决问题,此时this就是func2函数中的this,而func2是obj调用的,因此this实际指向obj。

_this=this

简单把this存一下即可

例六

var name = 'lisi'var obj = {name: 'zhangsan',func1: function() {console.log(this.name);},func2: function() {// this存一下在匿名函数里使用var _this = thissetTimeout(function() {_this.func1()}, 1000)}
}obj.func2() // zhangsan 

apply、call

apply和call都是用来改变this指向的,作用相同,用法稍微有点不同。

MDN中apply定义如下:

apply() 方法调用一个函数, 其具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数

用法:

func.apply(thisArg, ArrayArg) 

call定义如下:

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

用法:

func.call(thisArg, arg1, arg2, ...) 

详细用法见MDN。

例七

var name = 'lisi'var obj = {name: 'zhangsan',say: function(arg) {console.log(this.name, arg);}
}var func1 = obj.say // lisi 1
func1(1) 

此时this指向window,打印lisi 1。如果我们现在仍想要this指向obj,那么就可通过apply改变this:

var name = 'lisi'var obj = {name: 'zhangsan',say: function(arg) {console.log(this.name, arg);}
}var func1 = obj.say // zhangsan 2
func1.apply(obj, [2]) 

通过apply改变this指向,指向obj。然后通过一个数组传入调用时的参数。这就是apply用法的简单实例。call用法与其类似,只不过不是通过数组传参,而是需要显式传入多个参数。

var name = 'lisi'var obj = {name: 'zhangsan',say: function(arg) {console.log(this.name, arg);}
}var func1 = obj.say // zhangsan 3
func1.call(obj, 3) 

手动实现apply、call

理解了this、this指向、apply、call后我们可以思考一下如何手动实现apply、call。

手动实现apply

Function.prototype._apply = function(context) {// context是要绑定的this// this是调用的函数即func1if (typeof this !== "function") {throw new Error('只能在函数上调用')return}context = context || windowlet result = null// 把需要执行的函数赋给context,由context调用即可context.fn = thisif (arguments[1]) {result = context.fn(...arguments[1])} else {result = context.fn()}delete context.fnreturn result
}var name = 'lisi'var obj = {name: 'zhangsan',say: function(arg) {console.log(this.name, arg);}
}var func1 = obj.say // zhangsan 1
func1._apply(obj, [1]) 

总结步骤如下:

  • 判断调用对象是否为函数,即使是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。* 判断传入上下文对象是否存在,如果不存在,则设置为 window 。* 将函数作为上下文对象的一个属性。* 判断参数值是否传入* 使用上下文对象来调用这个方法,并保存返回结果。* 删除刚才新增的属性* 返回结果手动实现call

Function.prototype._call = function(context) {// context是要绑定的this// this是调用的函数即func1if (typeof this !== "function") {throw new Error('只能在函数上调用')return}context = context || windowconst arg = Array.from(arguments).splice(1)let result = null// 把需要执行的函数赋给context,由context调用即可context.fn = thisresult = context.fn(...arg)delete context.fnreturn result
}var name = 'lisi'var obj = {name: 'zhangsan',say: function(arg) {console.log(this.name, arg);}
}var func1 = obj.say // zhangsan 2
func1._call(obj, 2) 

最后

为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

相关文章:

说一下this,实现apply、call

理解this 在ES5中,this的指向始终坚持一个原理:“this永远指向最后调用它的那个对象”,切记这句话。下面看几个例子。 例一 var obj {name: zhangsan,say: function() {console.log(this.name);} }obj.say() // zhangsan 最基本的使用&am…...

华为OD机试真题Python实现【总最快检测效率】真题+解题思路+代码(20222023)

总最快检测效率 题目 在系统、网络均正常情况下,组织核酸采样员和志愿者对人群进行核酸检测筛查。 每名采样员的效率不同,采样效率为N人/小时。 由于外界变化,采样员的效率会以M人/小时为粒度发生变化,M 为采样效率浮动粒度, M=N*10%,输入保证N*10%的结果为整数。 采样…...

【历史上的今天】2 月 23 日:Enigma 密码机申请专利;戴尔电脑创始人出生;Mellanox 收购 EZchip

整理 | 王启隆 透过「历史上的今天」,从过去看未来,从现在亦可以改变未来。 今天是 2023 年 2 月 23 日,在 2006 年的今天,都灵冬奥会自由式滑雪男子空中技巧决赛在意大利都灵萨奥兹杜尔克斯滑雪场举行。中国选手韩晓鹏战胜众多好…...

新手入门吉他推荐,第一把吉他从这十款选绝不踩雷!初学者吉他选购指南【新手必看】

一、新手购琴注意事项: 1、预算范围 一把合适的吉他对于初学者来说会拥有一个很好的音乐启蒙。选一款性价比高,做工材料、音质和手感相对较好的吉他自然不会是一件吃亏的事。**初学者第一把琴的预算,我觉得最低标准也是要在500元起&#xf…...

XSS注入进阶练习篇(三) XSS原型链污染

XSS原型链污染1.原型链的概念1.1 构造函数的缺点1.2 prototype 属性的作用1.3 原型链1.4 constructor属性1.5 prototype和__proto__2. 原型链污染2.1 原型链污染是什么?2.2 原型链污染的条件2.3 原型连污染实例2.3.1 hackit 20182.3.2 challenge-04223.总结1.原型链…...

【Java基础 下】 025 -- 阶段项目(斗地主)

目录 斗地主 一、斗地主游戏1 -- 准洗发(控制台版) 1、准备牌 2、洗牌 3、发牌 4、看牌 二、斗地主游戏2 -- 给牌排序①(利用序号进行排序) 2、洗牌 3、发牌 4、看牌 三、斗地主游戏2 -- 给牌排序②(给每一张牌计算价值…...

华为OD机试真题Python实现【矩阵最值】真题+解题思路+代码(20222023)

题目 给定一个仅包含0和1的n*n二维矩阵 请计算二维矩阵的最大值 计算规则如下 每行元素按下标顺序组成一个二进制数(下标越大约排在低位), 二进制数的值就是该行的值,矩阵各行之和为矩阵的值允许通过向左或向右整体循环移动每个元素来改变元素在行中的位置 比如 [1,0,1,1,1]…...

TypeScript笔记(三)

前言 上一篇文章我们主要介绍了TypeScript的基本类型boolean、number、string、void、null和undefine,还介绍了任意类型any和联合类型,这篇文章我们将会了解对象类型Interface和数组的相关知识。 对象的类型——接口 在TypeScript中,我们使…...

C++(41)-低版本升级到VS2019项目时遇到的问题(2)

1.错误码:MSB8066 代码为3 QT 项目老版本升级到新版本造成的, 1.重新加载项目: 扩展->QT VS tools->Open QT project files-> 2.添加QT模块:QT Project-Settings -> QT Modules2.无法打开QT的头文件 3.…...

git 实战应用

基本使用1.1、使用git想要让 git 对一个目录进行版本控制需要一下步骤:进入要管理的文件夹执行初始化命令git init查看目录下的文件状态git status管理指定文件// 添加指定文件 git add ***.txt// 添加未被管理的所有文件 git add .生成版本git commit -m 描述信息提…...

Linux重启命令shutdown与reboot

在linux命令中reboot是重新启动,shutdown -r now是立即停止然后重新启动,都说他们两个是一样的,其实是有一定的区别的。 shutdown 命令可以安全地关闭或重启Linux系统,它在系统关闭之前给系统上的所有登录用户提示一条警告信息。…...

华为OD机试真题 用 C++ 实现 - 静态扫描最优成本

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…...

拿下宁王、迪王的湖南裕能,还能“狂飙”多远?

文|智能相对论作者|Kinki近日,磷酸铁锂正极材料龙头湖南裕能正式登陆A股,上市当天市值超过了400亿元,投资者中一签可赚1.49万元,可谓近年低迷的资本市场中一支“大肉签”。不过在 “开门红”之后,湖南裕能的股价便一路…...

STM32FreeRTOS - 按键实现任务挂起和恢复

STM32f103C8T6 FreeRTOS - 按键实现任务挂起和恢复,按键按下时,LED任务执行,led闪烁,当led任务挂起,Led停止闪烁。1.STM32CubeMX 创建任务1.1配置GPIO按键配置外部中断触发GPIO绿灯,红灯配置输出模式1.2配置…...

华为OD机试真题Python实现【判断牌型】真题+解题思路+代码(20222023)

判断牌型 题目 五张牌每张牌由牌大小和花色组成 牌大小2~10 J Q K A 花色四种 红桃 黑桃 梅花 方块 四种花色之一 判断牌型 牌型一 同花顺 同一花色的顺子 如红桃 2 红桃 3 红桃 4 红桃 5 红桃 6牌型二 四条 四张相同数字+单张 红桃 A 黑桃 A 梅花 A 方块 A 加黑桃 A牌型三 葫…...

Kafka(7):生产者详解

1 消息发送 1.1 Kafka Java客户端数据生产流程解析 1 首先要构造一个 ProducerRecord 对象,该对象可以声明主题Topic、分区Partition、键 Key以及值 Value,主题和值是必须要声明的,分区和键可以不用指定。 2 调用send() 方法进行消息发送。 3 因为消息要到网络上进行传输…...

FPGA纯verilog代码实现H.264/AVC视频解码,提供工程源码和技术支持

目录1、前言2、硬件H.264/AVC视频解码优势3、vivado工程设计架构4、代码架构分析5、vivado仿真6、福利:工程代码的获取1、前言 本设计是一种verilog代码实现的低功耗H.264/AVC解码器(baseline ),硬件ASIC设计,不使用任何GPP/DSP等内核&#…...

通俗神经网络

经典的全连接神经网络 经典的全连接神经网络来包含四层网络:输入层、两个隐含层和输出层,将手写数字识别任务通过全连接神经网络表示,如 图3 所示。 图3:手写数字识别任务的全连接神经网络结构输入层:将数据输入给神经…...

网络工程(一) 简单的配置

网络工程 简单的配置 需求 两台交换机 两台路由器 两台PC AR1配置静态路由 system-view [HUAWEI]sysname ar1 [ar1]interface g 0/0/0 [ar1-G…0/0/0]ip address 192.168.2.1 24 [ar1-G…0/0/0]quit [ar1]interface g 0/0/1 [ar1-G…0/0/1]ip address 192.168.3.1 24 [ar1-G…...

深度剖析数据在内存中的存储(上)

目录 1. 数据类型介绍 1.1 类型的基本归类 2. 整形在内存中的存储 2.1 原码、反码、补码 2.2 大小端介绍 2.3 一道小题 本章重点 1. 数据类型详细介绍 2. 整形在内存中的存储:原码、反码、补码 3. 大小端字节序介绍及判断 4. 浮点型在内存中的存储解析 正文…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

ArcGIS Pro+ArcGIS给你的地图加上北回归线!

今天来看ArcGIS Pro和ArcGIS中如何给制作的中国地图或者其他大范围地图加上北回归线。 我们将在ArcGIS Pro和ArcGIS中一同介绍。 1 ArcGIS Pro中设置北回归线 1、在ArcGIS Pro中初步设置好经纬格网等&#xff0c;设置经线、纬线都以10间隔显示。 2、需要插入背会归线&#xf…...

小智AI+MCP

什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析&#xff1a;AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github&#xff1a;https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...

深入解析光敏传感技术:嵌入式仿真平台如何重塑电子工程教学

一、光敏传感技术的物理本质与系统级实现挑战 光敏电阻作为经典的光电传感器件&#xff0c;其工作原理根植于半导体材料的光电导效应。当入射光子能量超过材料带隙宽度时&#xff0c;价带电子受激发跃迁至导带&#xff0c;形成电子-空穴对&#xff0c;导致材料电导率显著提升。…...