JavaScript 内的 this 指向
在 javascript 语言中, 有一个奇奇怪怪的 “关键字” 叫做 this为什么说它是 奇奇怪怪 呢, 是因为你写出 100 个 this, 可能有 100 个解释, 完全不挨边,但是, 在你的学习过程中, 搞清楚了 this 这个玩意, 那么会对你的开发生涯有很大帮助的,接下来咱们就开始一点一点的认识一下 this
this 初认识
看到 this, 先给他翻译过来 "这个"到底啥意思呢 ?
饭桌上, 你妈和你说, 你多吃点的这个
商店里, 你媳妇和你说, 这个包 这个包 这个包 我都要
宴会上, 你爸和人介绍说, 这个傻小子是我儿子
你看, 每一句话上都有 “这个”, 但是每个 “这个” 都是一个意思吗?并不,就像我们 js 内的 this 一样, 每一个 this 的意思都不一样,但是我们会发现,在说话的过程中, “这个” 是和我们说话的手势有关系在 js 内一个道理,this 的意思是和代码的 “手势” 有关系例子 :
当你媳妇手指着一个 LV 包的时候, 说的 “这个” 指代的就是 LV包
当你妈指着鱼香肉丝的时候说 “这个” 指代的就是 鱼香肉丝
所以在 javascript 内的 this 是要看 “说这句话的代码手指向哪里了”
看看下面一段代码
var box = document.querySelector('#box')box.onclick = function () {console.log(this)
}
当你点击 box 这个元素的时候, 会触发后面的函数,然后函数一执行, 就会在控制台打印一下 this,这里的 this 就是 box 这个元素,这就是一个非常简单的 this 指向的例子了
接下来我们就开始详细学习一下 this
给你个概念 , this , 是一个指针形变量, 它动态的指向当前函数的运行环境,“什么鬼东西, 我听不懂啊”,给一个私人的解释 : “根据 this 所在的函数是如何被调用的来决定 this 是什么”
举个例子来看一下
function fn() {console.log(this)
}
fn()// this 就是 window
因为 this 是在 fn 函数内, 所以 fn 函数的调用方式就决定了这个 this 是什么
function a() {function b() {console.log(this)}b()
}
a()// this 就是 window
因为 this 是在 b 函数内, 所以 b 函数的调用方式决定了 this 是什么, 和 a 函数没关系,就是这个意思,最后, 根据这些年的经验总结给出一个私人的概念, 要牢记
函数的 this
和函数定义在哪没关系
和函数怎么定义没关系
只看这个函数的调用方式
箭头函数除外
对象调用对象调用, 就是利用一个对象作为宿主来调用函数最简单的方式就是把函数写在一个对象内, 利用对象来调用
// 对象内写一个函数
const obj = {fn: function () { console.log(this) }
}// 调用这个函数
obj.fn()
这时候, 我们调用了和这个对象内的 fn 函数
调用方式就是利用对象调用的函数, 所以在这个函数内的 this 就是 obj 这个对象,换句话说, 只要在这个函数内, 只要出现 this 就是这个对象
全局调用
顾名思义, 全局调用就是直接调用一个全局函数
function fn() {console.log(this)
}fn()
此时这个函数内的 this 就是 window,可能有的小伙伴觉得疯了,但是我们仔细思考一下, 你会发现,其实 fn 因为是在全局上的, 那么其实调用的完整写法可以写成 window.fn(),此时就回到了之前对象调用那条路上, 这样就通顺了
奇怪的调用
这个时候, 有的小伙伴可能会想到一个问题, 如果这个函数不放在全局呢 ?
const obj = {fn: function () {function fun() {console.log(this)}fun()}
}obj.fn()
此时的 this 应该是什么呢 ?
按照之前的思路思考,○ obj.fn() 确实调用了函数, 但是 this 不是在 obj.fn 函数内, 是在 fun 函数内,○ fun() 确实也调用了函数, 但是我没有办法写成 window.fun(),○ 那么 this 到底是不是 window 呢, 还是应该是 obj 内
答案确实是 window, 这又是为什么呢 ?
捋一下思路
说到这里, 我们会发现,this 真的是好奇怪哦 o( ̄︶ ̄)o 搞不定了,要是按照这个方式, 我来回来去的得记多少种, 谁会记得下来呢
接下来(划重点)
我用写代码三十年的经验给你总结出来了一些内容, 希望你能牢记
this 的个人经验
首先, this 在各种不同的情况下会不一样,那么从现在开始我把我总结的内容毫无保留的传授给你
经验一 :
在 js 的非严格模式下适用
在非箭头函数中适用
不管函数定义在哪, 不管函数怎么定义, 只看函数的调用方式
只要我想知道 this 是谁
就看这个 this 是写在哪个函数里面
这个函数是怎么被调用的
观察 this 在哪个函数内
function fn() {console.log(this)
}// this 在函数 fn 内, 就看 fn 函数是怎么被调用的就能知道 this 是谁
const obj = {fn: function () {console.log(this)}
}// this 在 obj.fn 函数内, 就看这个函数怎么被调用的就能知道 this 是谁
const obj = {fn: function () {function fun() {console.log(this)}}
}// 这个 this 是在 fun 函数内
// 如果你想知道这个 this 是谁
// 和 obj.fn 函数没有关系, 只要知道 fun 函数是怎么被调用的就可以了
一定要注意 : 你想知道的 this 在哪个函数内, 就去观察哪个函数的调用方式就好了一些常见的函数调用方式
普通调用
调用方式 : 函数名()
this 是 window
只要你书写 “函数名()” 调用了一个函数, 那么这个函数内的 this 就是 window
function fn() {console.log(this)
}
fn()
// 这里就是 fn() 调用了一个函数, 那么 fn 内的 this 就是 window
const obj = {fn: function () {function fun() {console.log(this)}fun()}
}
obj.fn()
// 这里的 this 因为是在 fun 函数内
// fun() 就调用了这个 fun 函数
// 所以不用管 fun 函数写在了哪里
// 这个 fun 函数内的 this 就是 window
2,对象调用
调用方式:
对象.函数名()
对象’函数名’
this 就是这个对象, 对象叫啥, 函数内的 this 就叫啥
const obj = {fn: function () {console.log(this)}
}
obj.fn()
// 因为 obj.fn() 调用了这个函数, 所以 obj.fn 函数内的 this 就是 obj
const xhl = {fn: function () {console.log(this)}
}
xhl.fn()
// 因为 obj.fn() 调用了这个函数, 所以 xhl.fn 函数内的 this 就是 xhl
function fn() {const xhl = {fn: function () {console.log(this)}}xhl.fn()
}fn()
// 因为我们要观察的 this 是在 xhl.fn 这个函数内
// 所以只需要关注这个函数是如何被调用的即可
// 因为是 xhl.fn 调用了和这个函数, 所以函数内的 this 就是 xhl
3,定时器调用
调用方式
setTimeout(function () {}, 1000)
setInterval(function () {}, 1000)
this 就是 window
一个函数不管是怎么定义的, 只要被当做定时器处理函数使用, this 就是 widnow
setTimeout(function () {console.log(this)
}, 1000)
// 这里的 this 就是 window
setInterval(function () {console.log(this)
}, 1000)
// 这里的 this 就是 window
const xhl = {fn: function () {console.log(this)}
}setTimeout(xhl.fn, 1000)
// 这里的 xhl.fn 函数不是直接书写 xhl.fn() 调用的
// 而是给到了 setTimeout 定时器处理函数
// 所以这里的 this 就是 window
4,事件处理函数
调用方式
事件源.on事件类型 = 事件处理函数
事件源.addEventListener(事件类型, 事件处理函数)
this 就是 事件源
只要是作为事件处理函数使用, 那么该函数内的 this 就是 事件源奥,对了,事件就是:在事件中,当前操作的那个元素就是事件源
box.onclick = function () {console.log(this)
}
// 这里的 this 就是 box
box.addEventListener('click', function () {console.log(this)
})
// 这里的 this 就是 box
const xhl = {fn: function () {console.log(this)}
}box.addEventListener('click', xhl.fn)
// 这里的 xhl.fn 函数不是直接书写 xhl.fn() 调用的
// 而是给到了 事件, 被当做了事件处理函数使用
// 所以这里的 this 就是 事件源box
const xhl = {fn: function () {console.log(this)}
}box.onclick = xhl.fn
// 这里的 xhl.fn 函数不是直接书写 xhl.fn() 调用的
// 而是给到了 事件, 被当做了事件处理函数使用
// 所以这里的 this 就是 事件源box
5,构造函数调用
调用方式
new 函数名()
this 就是该构造函数的当前实例
只要和 new 关键字调用了, this 就是实例对象
function fn() {console.log(this)
}const f = new fn()
// 这里的因为 fn 函数和 new 关键字在一起了
// 所以这里的 this 就是 fn 函数的实例对象
// 也就是 f
const xhl = {fn: function () {console.log(this)}
}const x = new xhl.fn()
// 这里的 xhl.fn 也是因为和 new 关键字在一起了
// 所以这里的 this 就是 xhl.fn 函数的实例对象
// 也就是 x
记清楚原则 :
不管函数在哪定义,不管函数怎么定义,只看函数的调用方式
经验二 :
在严格模式下适用,其实只有一个,全局函数没有 this, 是 undefined,其他的照搬经验一就可以了
非严格模式
// 非严格模式
function fn() {console.log(this)
}
fn()
// 因为是在非严格模式下, 这里的 this 就是 window
2.严格模式
// 严格模式
'use strict'
function fn() {console.log(this)
}
fn()
// 因为是在严格模式下, 这里的 this 就是 undefined
记清楚原则 :
严格模式下,全局函数没有 this,是个 undefiend
经验三 :
专门来说一下箭头函数,其实也只有一条
推翻之前的所有内容,箭头函数内没有自己的 this,箭头函数内的 this 就是外部作用域的 this
换句话说, 当你需要判断箭头函数内的 this 的时候,和函数怎么调用没有关系了,要看函数定义在什么位置
// 非箭头函数
const xhl = {fn: function () {console.log(this)}
}
xhl.fn()
// 因为是 非箭头函数, 所以这里的 this 就是 xhl// ==========================================================// 箭头函数
const xhl = {fn: () => {console.log(this)}
}
xhl.fn()
// 因为是 箭头函数, 之前的经验不适用了
// 这个函数外部其实就是全局了, 所以这里的 this 就是 window
// 非箭头函数
box.onclick = function () {console.log(this)
}
// 因为是 非箭头函数, 这里的 this 就是 box// ==========================================================// 箭头函数
box.onclick = () => {console.log(this)
}
// 因为是 箭头函数
// 这个函数外部就是全局了, 所以这里的 this 就是 window
// 非箭头函数
const obj = {fn: function () {function fun() {console.log(this)}fun()}
}
obj.fn()
// 因为是 非箭头函数, 所以 fun 函数内的 this 就是 window// ==========================================================// 箭头函数
const obj = {fn: function () {const fun = () => {console.log(this)}fun()}
}
obj.fn()
// 因为是 箭头函数
// 那么这个 fun 外面其实就是 obj.fn 函数
// 所以只要知道了 obj.fn 函数内的 this 是谁, 那么 fun 函数内的 this 就出来了
// 又因为 obj.fn 函数内的 this 是 obj
// 所以 fun 函数内的 this 就是 obj
记清楚原则 :
只要是箭头函数,不管函数怎么调用,就看这个函数定义在了哪里
最后
好了,按照以上三个经验, 记清楚原则,那么在看到 this 就不慌了
相关文章:
JavaScript 内的 this 指向
在 javascript 语言中, 有一个奇奇怪怪的 “关键字” 叫做 this为什么说它是 奇奇怪怪 呢, 是因为你写出 100 个 this, 可能有 100 个解释, 完全不挨边,但是, 在你的学习过程中, 搞清楚了 this 这个玩意, 那么会对你的开发生涯有很大帮助的,接下来咱们就…...
Java多种方法实现等待所有子线程完成再继续执行
简介 在现实世界中,我们常常需要等待其它任务完成,才能继续执行下一步。Java实现等待子线程完成再继续执行的方式很多。我们来一一查看一下。 Thread的join方法 该方法是Thread提供的方法,调用join()时,会阻塞主线程࿰…...
制造企业数字化工厂建设步骤的建议
随着工业4.0、中国制造2025的深度推进,越来越多的制造企业开始迈入智能制造的领域,那数字工厂要从何入手呢? 数字工厂规划的核心,也正是信息域和物理域这两个维度,那就从这两个维度来进行分析,看如何进行数…...
网上鲜花交易平台,可运行
文章目录项目介绍一、项目功能介绍1、用户模块主要功能包括:2、商家模块主要功能包括:3、管理员模块主要功能包括:二、部分页面展示1、用户模块部分功能页面展示2、商家模块部分功能页面展示3、管理员模块部分功能页面展示三、部分源码四、底…...
【实战】用 Custom Hook + TS泛型实现 useArray
文章目录一、题目二、答案(非标准)三、关键知识点1.Custom Hook关键点案例useMountuseDebounce2.TS 泛型关键点一、题目 完善自定义 Hook —— useArray ,使其能够完成 tryUseArray 组件中测试的功能: 入参:数组返回…...
【LeetCode】剑指 Offer(18)
目录 题目:剑指 Offer 35. 复杂链表的复制 - 力扣(Leetcode) 题目的接口: 解题思路: 代码: 过啦!!! 写在最后: 题目:剑指 Offer 35. 复杂链…...
Kubernetes节点运行时从Docker切换到Containerd
由于k8s将于1.24版本弃用dockershim,所以最近在升级前把本地的k8s切换到了Containerd运行时,目前我的k8s版本是1.22.5,一个master,二个Node的配置,以下做为一个操作记录日志整理,其它可以参考官网文档。 在…...
【编程基础之Python】12、Python中的语句
【编程基础之Python】12、Python中的语句Python中的语句赋值语句条件语句循环语句for循环while循环continue语句break语句continue与break的区别函数语句pass语句异常处理语句结论Python中的语句 Python是一种高级编程语言,具有简单易学的语法,适用于各…...
android h5餐饮管理系统myeclipse开发mysql数据库编程服务端java计算机程序设计
一、源码特点 android h5餐饮管理系统是一套完善的WEBandroid设计系统,对理解JSP java,安卓app编程开发语言有帮助(系统采用web服务端APP端 综合模式进行设计开发),系统具有完整的源代码和数据库,系统主要…...
容易混淆的嵌入式(Embedded)术语
因为做嵌入式开发工作虽然跳不出电子行业,但还是能接触到跨度较大的不同行当,身处不同的圈子。诸如医疗,银行,车载,工业;亦或者手机,PC,专用芯片;甚至可能横跨系统开发、…...
Nodejs 中 JSON 和 YAML 互相转换
JSON 转换成 YAML 1. 安装 js-yaml 库: npm install js-yaml2. 在程序中引入依赖库 const yaml require(js-yaml);3. 创建一个 js 对象, 代表 json 数据 const jsonData {name: John,age: 30,city: New York };4. 使用 yaml.dump() 把 js 对象转换成 YAML, 返回 YAML 字符…...
C++入门教程||C++ 修饰符类型||C++ 存储类
C 修饰符类型 C 允许在 char、int 和 double 数据类型前放置修饰符。修饰符用于改变基本类型的含义,所以它更能满足各种情境的需求。 下面列出了数据类型修饰符: signedunsignedlongshort 修饰符 signed、unsigned、long 和 short 可应用于整型&#…...
Android开发面试:Java知识答案精解
目录 Java 集合 集合概述 HashMap ConcurrentHashMap 泛型 反射 注解 IO流 异常、深浅拷贝与Java8新特性 Java异常 深浅拷贝 Java8新特性 并发 线程 线程池 锁 volatile JVM 内存区域 内存模型 类加载机制 垃圾回收机制 如何判断对象已死 Java 集合 …...
Windows上一款特别好用的画图软件
安装 废话不多说,打开windows的应用商店,搜索draw.io,点击获取即可。 画图 draw.io的布局左边是各种图形组件,中间是画布,右边是属性设置,文件扩展名是.drawio。 点击左边列表中的图形可以将它添加到画…...
html--学习
javascrapt交互,网页控制JavaScript:改变 HTML 图像本例会动态地改变 HTML <image> 的来源(src):点亮灯泡<script>function changeImage() {elementdocument.getElementById(myimage) #内存变量࿰…...
关于递归处理,应该怎么处理,思路是什么?
其实问题很简单,就是想要循环遍历整个data对象,来实现所有name转成label,但是想到里面还有children属性,整个children里面可能还会嵌套很多很多的name,如此循环,很难搞,知道使用递归,…...
重磅!牛客笔试客户端可防ChatGPT作弊
上线俩月,月活过亿。爆火的ChatGPT能代写文,撕代码,善玩梗,秒答题,几乎“无所不能”,争议也随之而来。调查显示,截至2023年1月,美国89%的大学生利用ChatGPT应付作业,53%的…...
春季训练营 | 前端+验证直通车-全实操项目实践,履历加成就业无忧
“芯动的offer”是2023年E课网联合企业全新推出集训培优班(线下),针对有一定基础(linux、verilog、uvm等)在校学生以及想要通过短时间的学习进入到IC行业中的转行人士,由资深IC设计工程师带教,通…...
2.详解URL
文章目录视图函数1.1endpoint简介1.2 装饰器注册路由源码浅析1.3 另一种注册路由的方式---app.add_url_rule()1.4 视图函数中添加自定义装饰器2 视图类2.1 视图类的基本写法3 详细讲解注册路由的参数3.1常用的参数3.2不常用的参数(了解)视图函数 1.1endpoint简介 endpint参数…...
Android特别的数据结构(二)ArrayMap源码解析
1. 数据结构 public final class ArrayMap<K,V> implements Map<K,V> 由两个数组组成,一个int[] mHashes用来存放Key的hash值,一个Object[] mArrays用来连续存放成对的Key和ValuemHashes数组按非严格升序排列初始默认容量为0减容ÿ…...
减少if else
1. 三目运算符 可以理解为条件 ?结果1 : 结果2 里面的?号是格式要求。也可以理解为条件是否成立,条件成立为结果1,否则为结果2。 实例: public String handle(int code) {if (code 1) {return "success";} else {return &quo…...
硕士毕业论文常见的排版小技巧
word排版陆续更新吧,更具我所遇到的一些小问题,总结上来 文章目录1.避免题注(图或者表的标题)与图或表格分不用页注意点:光标移动到表的题注后面2.设置论文的页眉关键点:需要将每一章节末尾,都要…...
JAVA开发(数据类型String和HasMap的实现原理)
在JAVA开发中,使用最多的数据类型恐怕是String 和 HasMap两种数据类型。在开发的过程中我们每天都使用的不亦乐乎。但是相信很多人都没有考虑过String数据类型的实现原理或者说是在数据结构中的存储原理,还有一个就是是HashMap,也很少有人去了…...
Hbase 映射到Hive
目录 一、环境配置修改 关闭掉hbase,zookeeper和hive服务 进入hive312/conf 修改hive-site.xml配置, 在代码最后添加配置 将hbase235的jar包全部拷贝到hive312的lib目录,并且所有的是否覆盖信息全部输入n,不覆盖 查看hive312下…...
14_MySQL视图
1. 常见的数据库对象2. 视图概述2.1 使用视图的好处视图一方面可以帮我们使用表的一部分而不是所有的表,另一方面也可以针对不同的用户制定不同的查询视图。比如,针对一个公司的销售人员,我们只想给他看部分数据,而某些特殊的数据…...
做程序界中的死神,斩魂刀始解
标题解读:标题中的死神,是源自《死神》动漫里面的角色,斩魂刀是死神的武器,始解是斩魂刀的初始解放形态,卐解是斩魂刀的觉醒解放形态,也是死神的大招。意旨做程序界中程序员的佼佼者,一步一步最…...
顺序表——“数据结构与算法”
各位CSDN的uu们你们好呀,今天小雅兰的内容是数据结构与算法里面的顺序表啦,在我看来,数据结构总体上是一个抽象的东西,关键还是要多写代码,下面,就让我们进入顺序表的世界吧 线性表 顺序表 线性表 线性表&…...
嵌入式Linux从入门到精通之第十六节:U-boot分析
简介 u-boot最初是由PPCBoot发展而来的,可以引导多种操作系统、支持多种架构的CPU,它对PowerPC系列处理器的支持最为完善,而操作系统则对Linux系统的支持最好目前已成为Armboot和PPCboot的替代品。 特点: 主要支持操作系统:Linux、NetBSD、 VxWorks、QNX、RTEMS、ARTOS、L…...
UART 串口通信
第18.1讲 UART串口通信原理讲解_哔哩哔哩_bilibili 并行通信 一个周期同时发送8bit的数据,占用引脚资源多 串行通信 串行通信的通信方式: 同步通信 同一时钟下进行数据传输 异步通信 发送设备和接收设备的时钟不同 但是需要约束波特率(…...
【硬件】P沟道和N沟道MOS管开关电路设计
场效应管做的开关电路一般分为两种,一种是N沟道,另一种是P沟道,如果电路设计中要应用到高端驱动的话,可以采用PMOS来导通。P沟道MOS管开关电路PMOS的特性,Vgs小于一定的值就会导通,当Vgs<0,即Vs>Vg,管…...
亚马逊html编辑器/网站整体优化
一、关于Redis Redis最为一款开源的key-value存储系统,自推出到现在一直受到编程人员的喜爱。它支持存储多种value类型,String 、List 、Set 、Zset 、Hash。这些数据类型都支持push/pop、add/remove 及取交集、并集、差集等操作,这些操作都是…...
wordpress插件table/手机网站快速建站
好的,这是一个简单的 Java for 循环: for (int i 0; i < 10; i) {System.out.println("当前循环次数: " i); }其中 int i 0 是初始化语句,i < 10 是循环条件,i 是每次循环后的计数器。循环执行 10 次ÿ…...
吉林省最新消息今天新增/杭州百度seo
提起美签,我相信很多朋友都会觉得犯怵,就我的一个朋友来讲,她是咱们中国人,但是男朋友是美国人,两人异地,分开了大约一年多,不过还保持很好的关系,实属难得。近期,男友即…...
日本 女做视频网站/信息流广告优化师培训
PXEKickstart无人值守安装服务无人值守安装系统简介部署DHCP服务程序安装DHCP服务程序编辑DHCP配置文件部署TFTP服务程序安装tftp服务程序部署SYSLinux服务程序配置自动挂载服务程序编辑主配置文件编辑子配置文件启动autofs程序进入挂载目录部署SYSLinux服务程序安装SYSLinux服…...
中国建设银行jcb卡网站/自助建站模板
前面给大家做一些扫描工具,今天小菜给大家带来了ARP欺骗工具。当然啦,工具实现起来也是几行代码呢!(是不是依旧如此简单)。这个可以让目标器断网,还可以把数据包转到自己机器上,自己机器开启转发数据包功能,这样就可以…...
广州网页制作平台/aso优化软件
所谓回调:就是A类中调用B类中的某个方法,然后B类中反骨来调用A类中的方法D,D这个方法就叫做回调方法。1、Class A实现了接口CallBack callback2、class A包含一个class B的引用b3、class B 有一个参数为callback的方法f(Callback callback)4、A的对象a调用B的方法f(…...