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

【JavaScript】this 指向

1、this 指向谁

多数情况下,this 指向调用它所在方法的那个对象。即谁调的函数,this 就归谁。

当调用方法没有明确对象时,this 就指向全局对象。在浏览器中,指向 window;在 Node 中,指向 Global。(严格模式下,指向 undefined)

this 的指向是在调用时决定的,而不是在书写时决定的。这点和闭包恰恰相反。

2、区分 “声明位置” 与 “调用位置”

js 是词法作用域模型,对象或方法,其生命周期只和声明位置有关。

示例:

// 声明位置
var me = {name: 'xiaohong',hello: function() {console.log(`${this.name}`)}
}
var you = {name: 'xiaoming',hello: me.hello
}// 调用位置
me.hello() 	// xiaohong
you.hello() // xiaoming

两次调用的 this 也就分别指向了 me 和 you。

// 声明位置
var me = {name: 'xiaohong',hello: function() {console.log(`${this.name}`)}
}
var name = 'xiaoming'
var hello = me.hello 
// 调用位置
me.hello() 	// xiaohong
hello() 		// xiaoming

me.hello 赋值给变量 hello 时,实际上是在创建一个新的函数引用,这个引用指向 me 对象中的 hello 方法。但是,这个新的引用(即变量 hello)并不保留与 me 对象的任何关联或绑定。

调用 hello() 时,是在全局作用域中调用这个函数,而不是作为 me 对象的方法调用。因此,在这个调用中,this 的值不会指向 me 对象。

// 声明位置
var me = {name: 'xiaohong',hello: function() {console.log(`${this.name}`)}
}
var you = {name: 'xiaoming',hello: function() {var targetFunc = me.hellotargetFunc()}
}
var name = 'xiaosan'
// 调用位置
you.hello() // xiaosan

调用一个对象的方法时(例如 me.hello()),this 在该方法内部指向调用该方法的对象(在这个例子中是 me)。但是,将一个方法赋值给一个变量(例如 var targetFunc = me.hello),然后像普通函数那样调用这个变量(例如 targetFunc()),this 就不会再指向原来的对象了。相反,在非严格模式下,this 会默认指向全局对象(在浏览器中是 window),而在严格模式下,this 会是 undefined

3、普通函数的this指向总结

① 默认绑定:

  • 在全局中声明的变量和函数(默认指向Window);

  • 函数独立调用时(声明式函数、匿名函数 / 赋值式的方式、闭包)(都是指向Window);

  • 立即执行函数、 setTimeout、setInterval 指向 window

② 隐式绑定:

  • 对象调用(也就是谁调用就是指向谁,所以就是指向调用这个函数的对象)

(存在隐式丢失的问题:函数赋值和参数赋值的情况);

  • 绑定的事件处理函数(指向的是绑定事件处理函数的标签);

③ 显式绑定:

  • call / apply / bind (指向第一个参数)

④ new绑定:

  • 构造函数中的this指向实例化出来的对象;

4、箭头函数

箭头函数内部是没有this指向的,箭头函数的this指向父级作用域的this;如果没有,则this指向的就是Window。

箭头函数注意事项:

  • 使用了箭头函数,this就不是指向window,而是父级(指向是可变的)

  • 不能够使用arguments对象

  • 不能用作构造函数,这就是说不能够使用new命令,否则会抛出一个错误

      var Foo = () => {console.log(this);};var a = new Foo(); // 报错Foo is not a constructor
    
  • 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数

示例:

function foo() {console.log(this) // obj对象// 情况一// function test() {//     console.log(this) // Window// }// test()// 情况二// function test() {//     console.log(this) // obj对象// }// test.call(this)// 情况三var test = () => {console.log(this) // obj对象}test()
}
var obj = {a: 1,foo: foo
}
obj.foo()
const obj = {sayThis: () => {console.log(this);}
};
// 因为JavaScript没有块作用域,所以在定义sayThis的时候,里面的this就绑到window上去了
obj.sayThis(); 	// window 
const globalSay = obj.sayThis;
globalSay(); 		// window 浏览器中的global对象
const liEle = document.querySelectorAll('li');
liEle.forEach((item, key) => {// 箭头函数的this指向的是父级程序// forEach()的this指向windowconsole.log('打印1', this) // Windowitem.addEventListener('click', () => {console.log('打印2', this) // Window})
})
const button = document.getElementById('btn');
button.addEventListener('click', () => {console.log(this) // Window
})
function Cat(title) {this.title = title
}
Cat.prototype.sayName = () => {console.log(this) // Windowreturn this.title
}
const cat = new Cat('我是标题啊');
console.log(cat.sayName()) // undefined
function foo() {console.log(this) // obj对象var test = () => {console.log(this) // obj对象}return test
}
var obj = {a: 1,foo: foo
}
obj.foo()()
function foo1() {console.log(this) // obj对象
}
var foo2 = () => {console.log(this) // Window
}
var obj = {a: 1,foo1: foo1,foo2: foo2
}
obj.foo1()
obj.foo2()
function foo1() {console.log(this) // obj2对象
}
var foo2 = () => {console.log(this) // Window
}
var obj = {a: 1,foo1: foo1,foo2: foo2
}
var obj2 = {a: 2
}
obj.foo1.call(obj2)
obj.foo2.call(obj2)
function foo() {console.log(this) // Windowvar test = () => {console.log(this) // Window}return test
}
var obj = {a: 1,foo: foo
}
var obj2 = {a: 2,foo: foo
}
foo().call(obj)
const obj = {// 普通函数:this指向调用它的对象fn1: function() {console.log(this) // {fn1: ƒ, fn2: ƒ, fn3: ƒ}},// 箭头函数:this指向是父级程序的this指向// 父级程序是obj对象,但只有函数有this,obj对象没有this// 父级程序没有this,指向的是windowfn2: () => {console.log(this) // Window对象}, // fn3是一个普通函数:this指向的是obj对象fn3: function() {// fn4是一个箭头函数:this指向的是父级程序的this指向// 父级程序是fn3,fn3的this指向的是obj对象,所以fn4箭头函数的this也是指向obj对象const fn4 = () => {console.log(this) // {fn1: ƒ, fn2: ƒ, fn3: ƒ}}fn4()}
}
obj.fn1()
obj.fn2()
obj.fn3()
var x = 11;
var obj = {x: 22,y: this,say: () => {console.log(this.x);}
}
obj.say();					// 11
console.log(obj.y);	// window

解析:obj 对象中的 this 指向的就是 window,也就是全局环境。所以obj.y打印的是window对象;**因为箭头函数中的 this 指向父级程序的指向。**从以上例子可以看出来,父级obj指向了window,所以this.x打印的是11

var a = 11;
function fn() {this.a = 22;let b = () => {console.log(this.a)}b();
}
var x = new fn();	// 22

解析:箭头函数中会往上寻找this,直到找到所代表的this为止。例子中,构造函数被实例化成为一个对象x,那x中的this指代的就是对象x本身,所以箭头函数this就代表x对象,x对象内部的a值为22,所以输出22。

var name = 'window'
var obj1 = {name: '1',fn1: function(){ console.log(this.name) },fn2: () => console.log(this.name),fn3: function (){return function(){console.log(this.name)}},fn4: function(){return () => console.log(this.name)}
}
var obj2 = {name: '2'
};obj1.fn1();                 // 1
obj1.fn1.call(obj2);        // 2
obj1.fn2();                 // window
obj1.fn2.call(obj2);        // window
obj1.fn3();                 // window
obj1.fn3().call(obj2);      // 2
obj1.fn3.call(obj2)();      // window
obj1.fn4();                 // 1
obj1.fn4().call(obj2);      // 1
obj1.fn4.call(obj2)();      // 2
function Foo() {getName = function () {alert(1);};return this;
}
Foo.getName = function () {alert(2);
};
Foo.prototype.getName = function () {alert(3);
};
var getName = function () {alert(4);
};
function getName() {alert(5);
}Foo.getName();						// 2
getName();								// 4
Foo().getName();					// 1
getName();								// 1new Foo.getName();				// 2
new Foo().getName();			// 3
new new Foo().getName();	// 3

解析:

预编译中声明提升:function getName(){} 属于函数声明式,提升到最前面。

所以,全局的getName被替换成为function(){ alert(4) }

执行完Foo()后,函数返回了this,this指向window。所以Foo().getName()相当于window.getName(),而函数中的getName是全局的,执行函数的时候,替换掉了之前的输出为4的getName,当前就是输出1

9、资料

  • 【前端面经】JS this 基本指向原则解析

  • 普通函数和箭头函数this 指向的区别?如何改变this指向?

相关文章:

【JavaScript】this 指向

1、this 指向谁 多数情况下,this 指向调用它所在方法的那个对象。即谁调的函数,this 就归谁。 当调用方法没有明确对象时,this 就指向全局对象。在浏览器中,指向 window;在 Node 中,指向 Global。&#x…...

DB Type

P位 p 1时段描述符有效,p 0时段描述符无效 Base Base被分成了三个部分,按照实际拼接即可 G位 如果G 0 说明描述符中Limit的单位是字节,如果是G 1 ,那么limit的描述的单位是页也就是4kb S位 S 1 表示代码段或者数据段描…...

python-返回函数

Python的函数不但可以返回int、str、list、dict等数据类型,还可以返回函数! 例如,定义一个函数 f(),我们让它返回一个函数 g,可以这样写: def f()&#xff…...

python语言基础-5 进阶语法-5.2 装饰器-5.2.1 闭包

声明:本内容非盈利性质,也不支持任何组织或个人将其用作盈利用途。本内容来源于参考书或网站,会尽量附上原文链接,并鼓励大家看原文。侵删。 5.2 装饰器 python中的装饰器相当于java中的注解。装饰器用于为函数添加某些修饰性、…...

用vscode编写verilog时,如何有信号定义提示、信号定义跳转(go to definition)、模块跳转(跨文件跳转)这些功能

(一)方法一:安装插件SystemVerilog - Language Support 安装一个vscode插件即可,插件叫SystemVerilog - Language Support。虽然说另一个插件“Verilog-HDL/SystemVerilog/Bluespec SystemVerilog”也有信号提示及定义跳转功能&am…...

MQTT+Springboot整合

1.mqttconfig配置(配置参数是从数据库查出来的) package com.terminal.dc3.api.center.manager.config;import com.collection.common.utils.StringUtils; import com.collection.system.mapper.MqttConfigMapper; import lombok.Data; import org.springframework.beans.fact…...

ERROR TypeError: AutoImport is not a function

TypeError: AutoImport is not a function 原因:unplugin-auto-import 插件版本问题 Vue3基于Webpack,在vue.config.js中配置 当unplugin-vue-components版本小于0.26.0时,使用以下写法 const { defineConfig } require("vue/cli-se…...

软考教材重点内容 信息安全工程师 第 3 章 密码学基本理论

(本章相对老版本极大的简化,所有与算法相关的计算全部删除,因此考试需要了解各个常 用算法的基本参数以及考试中可能存在的古典密码算法的计算,典型的例子是 2021 和 2022 年分别考了 DES 算法中的 S 盒计算,RSA 中的已…...

微信小程序 https://thirdwx.qlogo.cn 不在以下 downloadFile 合法域名列表中

授权登录后,拿到用户头像进行加载,但报错提示: https://thirdwx.qlogo.cn 不在以下 downloadFile 合法域名列表中 解决方法一(未完全解决,临时处理):在微信开发者工具将不校验...勾上就可以访问…...

Linux性能优化之火焰图的起源

Linux火焰图的起源与性能优化专家 Brendan Gregg 密切相关,他在 2011 年首次提出这一工具,用于解决性能分析过程中可视化和数据解读的难题。 1. 背景:性能优化的需求 在现代计算中,性能优化往往需要对程序执行中的热点和瓶颈进行…...

《Markdown语法入门》

文章目录 《Markdown语法入门》1.标题2.段落2.1 换行2.2分割线 3.文字显示3.1 字体3.2 上下标 4. 列表4.1无序列表4.2 有序列表4.3 任务列表 5. 区块显示6. 代码显示6.1 行内代码6.2 代码块 7.插入超链接8.插入图片9. 插入表格 《Markdown语法入门》 【Typora 教程】手把手教你…...

Controller Baseband commands速览

目录 一、设备连接与通信控制类(34条) 1.1. 连接参数相关 1.1.1. 连接建立超时设置 1.1.2. 链路监督超时设置 1.1.3. Page操作超时设置 1.1.4. 扩展Page操作超时设置 1.1.5. 安全连接主机支持 1.2. 扫描操作相关 1.2.1. 扫描启用与禁用 1.2.2.…...

Redisson 3.39.0 发布

Redisson 3.39.0 发布,官方推荐的 Redis 客户端 Redisson 3.38.0 ,一个 Java 编写的 Redis 客户端。 此版本更新内容如下: RTopic 对象的 partitioning 实现 RShardedTopic对象的 partitioning 实现 RReliableTopic 对象的 partitioning 实…...

高阶C语言补充:柔性数组

C99中,结构体中最后一个元素允许时未知大小的数组,这就叫做柔性数组成员。 vs编译器也支持柔性数组。 之所以把柔性数组单独列出,是因为: 1、柔性数组是建立在结构体的基础上的。 2、柔性数组的使用用到了动态内存分配。 这使得柔…...

S32K324信息安全-使用IC5000/IC5700进行debug口解锁

文章目录 前言winIDEA配置参考 前言 由于信息安全要求,需要对debug口(JTAG)进行加密,本文介绍基于固定密码的方式,使用IC5000/IC5700进行debug口解锁的方法 winIDEA配置 点击 Hardware | CPU Options | Reset | Ini…...

简单实现QT对象的[json]序列化与反序列化

简单实现QT对象的[json]序列化与反序列化 简介应用场景qt元对象系统思路实现使用方式题外话 简介 众所周知json作为一种轻量级的数据交换格式,在开发中被广泛应用。因此如何方便的将对象数据转为json格式和从json格式中加载数据到对象中就变得尤为重要。 在python类…...

Unity肢体控制(关节控制)

前面的基础搭建网上自己搜,我这个任务模型网上也有,可以去官网看看更多模型,这里只讲述有模型如何驱动肢体的操作方式 第一步:创建脚本 第二步:创建Rig Builder 建空容器 加部件(Rig),加了之后…...

Node.js | Yarn下载安装与环境配置

一、安装Node.js Yarn 是 Node.js 下的包管理工具,因此想要使用 Yarn 就必须先下载 Node.js。 推荐参考:Node.js | npm下载安装及环境配置教程 二、Yarn安装 打开cmd,输入以下命令: npm install -g yarn检查是否安装成功&…...

WPF如何全局应用黑白主题效果

灰白色很多时候用于纪念,哀悼等。那么使用 WPF如何来做到这种效果呢?要实现的这种效果,我们会发现,它其实不仅仅是要针对图片,而是要针对整个窗口来实现灰白色。 如果只是针对图片的话,我可以可以对图片进…...

[Qt] Qt删除文本文件中的某一行

需求 我们经常读一个文件或者直接往一个空白文件中写文本&#xff0c;那么该如何使用Qt在一个文本文件中删除某一行 代码 #include <QCoreApplication> #include <QIODevice> #include <QFile> #include <QTextStream> #include <QString> #i…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

区块链技术概述

区块链技术是一种去中心化、分布式账本技术&#xff0c;通过密码学、共识机制和智能合约等核心组件&#xff0c;实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点&#xff1a;数据存储在网络中的多个节点&#xff08;计算机&#xff09;&#xff0c;而非…...