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

搞懂 JS this、call、apply、bind

搞懂 JS this、call、apply、bind

javascript 的 this

ECMAScript 规范中这样写:
this 关键字执行为当前执行环境的 ThisBinding。
MDN 上这样写:
In most cases, the value of this is determined by how a function is called.
在绝大多数情况下,函数的调用方式决定了 this 的值。
可以这样理解,在 JavaScript 中,this 的指向是调用时决定的,而不是创建时决定的,这就会导致 this 的指向会让人迷惑,简单来说,this 具有运行期绑定的特性。

首先需要理解调用位置,调用位置就是函数在代码中被调用的位置,而不是声明的位置。

通过分析调用栈(到达当前执行位置所调用的所有函数)可以找到调用位置。

全局上下文
在全局执行上下文中 this 都指代全局对象。

this等价于window对象
var === this. === winodw.
console.log(window === this); // true
var a = 1;
this.b = 2;
window.c = 3;
console.log(a + b + c); // 6

在浏览器里面 this 等价于 window 对象,如果你声明一些全局变量,这些变量都会作为 this 的属性。

函数上下文
在函数内部,this 的值取决于函数被调用的方式。
直接调用
this 指向全局变量。

function foo(){return this;
}
console.log(foo() === window); // true

如何改变 this 指向

call()、apply()

this 指向绑定的对象上。

var person = {name: "test",age: 25
};
function say(job){console.log(this.name+":"+this.age+" "+job);
}
say.call(person,"FE"); // test:25
say.apply(person,["FE"]); // test:25

可以看到,定义了一个 say 函数是用来输出 name、age 和 job,其中本身没有 name 和 age 属性,我们将这个函数绑定到 person 这个对象上,输出了本属于 person 的属性,说明此时 this 是指向对象 person 的。

如果传入一个原始值(字符串、布尔或数字类型)来当做 this 的绑定对象, 这个原始值会被转换成它的对象形式(new String()),这通常被称为“装箱”。

call 和 apply 从 this 的绑定角度上来说是一样的,唯一不同的是它们的第二个参数。

bind()

this 将永久地被绑定到了 bind 的第一个参数。

bind 和 call、apply 有些相似。

var person = {name: "test",age: 25
};
function say(){console.log(this.name+":"+this.age);
}
var f = say.bind(person);
console.log(f());

call 和 apply 有什么区别

call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。

当调用一个函数时,可以赋值一个不同的 this 对象。this 引用当前对象,即 call 方法的第一个参数。

通过 call 方法,你可以在一个对象上借用另一个对象上的方法,比如 Object.prototype.toString.call([]),就是一个 Array 对象借用了 Object 对象上的方法。

语法 fun.call(thisArg[, arg1[, arg2[, …]]])

thisArg

在 fun 函数运行时指定的 this 值。需要注意的是下面几种情况

(1)不传,或者传 null,undefined, 函数中的 this 指向 window 对象
(2)传递另一个函数的函数名,函数中的 this 指向这个函数的引用,并不一定是该函数执行时真正的 this 值 (3)值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象,如 String、Number、Boolean
(4)传递一个对象,函数中的 this 指向这个对象

arg1, arg2, …

指定的参数列表。

语法与 call() 方法的语法几乎完全相同,唯一的区别在于,apply 的第二个参数必须是一个包含多个参数的数组(或类数组对象)。apply 的这个特性很重要,

在调用一个存在的函数时,你可以为其指定一个 this 对象。 this 指当前对象,也就是正在调用这个函数的对象。 使用 apply, 你可以只写一次这个方法然后在另一个对象中继承它,而不用在新对象中重复写该方法。

语法:fun.apply(thisArg[, argsArray])

bind() 函数会创建一个新函数(称为绑定函数)

bind 是 ES5 新增的一个方法
传参和 call 或 apply 类似
不会执行对应的函数,call 或 apply 会自动执行对应的函数
返回对函数的引用
语法 fun.bind(thisArg[, arg1[, arg2[, …]]])

下面例子:当点击网页时,EventClick 被触发执行,输出 JSLite.io p1 p2, 说明 EventClick 中的 this 被 bind 改变成了 obj 对象。如果你将 EventClick.bind(obj,‘p1’,‘p2’) 变成 EventClick.call(obj,‘p1’,‘p2’) 的话,页面会直接输出 JSLite.io p1 p2

var obj = {name:'JSLite.io'};
/*** 给document添加click事件监听,并绑定EventClick函数* 通过bind方法设置EventClick的this为obj,并传递参数p1,p2*/
document.addEventListener('click',EventClick.bind(obj,'p1','p2'),false);
//当点击网页时触发并执行
function EventClick(a,b){console.log(this.name, //JSLite.ioa, //p1b  //p2)
}

模拟实现 call

Function.prototype.call2 = function (context) {var context = context || window;context.fn = this;var args = [];for(var i = 1, len = arguments.length; i < len; i++) {args.push('arguments[' + i + ']');}var result = eval('context.fn(' + args +')');delete context.fnreturn result;
}// 测试一下
var value = 2;var obj = {value: 1
}function bar(name, age) {console.log(this.value);return {value: this.value,name: name,age: age}
}bar.call(null); // 2console.log(bar.call2(obj, 'kevin', 18));
// 1
// Object {
//    value: 1,
//    name: 'kevin',
//    age: 18
// }

模拟实现 apply

Function.prototype.apply = function (context, arr) {var context = Object(context) || window;context.fn = this;var result;if (!arr) {result = context.fn();}else {var args = [];for (var i = 0, len = arr.length; i < len; i++) {args.push('arr[' + i + ']');}result = eval('context.fn(' + args + ')')}delete context.fnreturn result;
}

相关文章:

搞懂 JS this、call、apply、bind

搞懂 JS this、call、apply、bind javascript 的 this ECMAScript 规范中这样写&#xff1a; this 关键字执行为当前执行环境的 ThisBinding。 MDN 上这样写&#xff1a; In most cases, the value of this is determined by how a function is called. 在绝大多数情况下&…...

力扣209长度最小的子数组

209. 长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, …, numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0 。 示例 1&#xf…...

【mysql是怎样运行的】-InnoDB数据页结构

文章目录1. 数据库的存储结构&#xff1a;页1.1 磁盘与内存交互基本单位&#xff1a;页1.2 页结构概述1.3 页的上层结构2. 页的内部结构2.1 第1部分&#xff1a;文件头部和文件尾部2.1.1 File Header&#xff08;文件头部&#xff09;&#xff08;38字节&#xff09;2.1.2 File…...

VIM实用指南(10)语法自动补全插件coc.nvim

最近发现了一个新的自动补全插件coc.nvim异步&#xff0c;nodejs后端&#xff0c;配合它自身的lsp支持用起来非常舒服&#xff0c;同样也支持lsp和snippets&#xff0c;强烈推荐&#xff0c;值得一试。 1、使用vimplug安装插件 1.进入coc.nvim 在github的主页https://github.…...

【Vue3 第二十二章】过渡动画

一、基本用法 <Transition> 是一个内置组件&#xff0c;这意味着它在任意别的组件中都可以被使用&#xff0c;无需注册。它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。进入或离开可以由以下的条件之一触发&#xff1a; 由 v-if 所触发的切换由 v-…...

【linux】:进程状态(僵尸进程等)以及环境变量

文章目录 前言一.进程状态 进程的优先级二.环境变量总结前言 本篇文章是接着上一篇【linux】:进程概念的后续&#xff0c;对于有基础的同学可以直接看这篇文章&#xff0c;对于初学者来说强烈建议大家从上一篇的概念开始看起&#xff0c;上一篇主要解释了冯诺依曼体系以及操…...

【C语言——练习题】指针,你真的学会了吗?

✨✨✨✨如果文章对你有帮助记得点赞收藏关注哦&#xff01;&#xff01;✨✨✨✨ 文章目录✨✨✨✨如果文章对你有帮助记得点赞收藏关注哦&#xff01;&#xff01;✨✨✨✨一维数组练习题&#xff1a;字符数组练习题&#xff1a;字符指针练习题&#xff1a;二维数组练习题&am…...

Linux用户空间与内核空间通信(Netlink通信机制)

一&#xff0c;什么是Netlink通信机制 Netlink是linux提供的用于内核和用户态进程之间的通信方式。但是注意虽然Netlink主要用于用户空间和内核空间的通信&#xff0c;但是也能用于用户空间的两个进程通信。只是进程间通信有其他很多方式&#xff0c;一般不用Netlink。除非需要…...

3.3日报

今天写技术文档 跟需求对其 找负责人要上游数据接口&#xff0c;并处理更新时间问题 遇到的问题&#xff1a; 1.调用上游接口&#xff0c;需要token&#xff0c;而我的数据看板是不需要登录的&#xff0c;需要其他途径获取token 不同数据使用的接口不在一个项目中&#xff…...

并发编程-进程

并发编程-进程 进程创建启动 python提供了multiprocessing模块来支持多进程 multiprocessing.Process(targettask, args(arg,))用于创建进程 Process类相关方法 start() 启动进程join() 等待进程结束 启动子线程 【注意】线程启动代码块要放在__name__ __main__下 方式…...

LeetCode196_196. 删除重复的电子邮箱

LeetCode196_196. 删除重复的电子邮箱 一、描述 SQL架构 Create table If Not Exists Person (Id int, Email varchar(255)) Truncate table Person insert into Person (id, email) values (1, johnexample.com) insert into Person (id, email) values (2, bobexample.com…...

Auto.js Pro 替代品

Time : 2023年3月2日04:20:31 Mode : 持续更新中,排名不分先后.想起啥写啥 By : MemoryErHero NewTime: 2023年3月4日12:11:49 NO13. Autox.js文档&#xff1a; http://doc.autoxjs.com/ NO14. AutoJs6项目文档&#xff1a;https://github.com/SuperMonster003/AutoJs6 NO…...

红日(vulnstack)2 内网渗透ATTCK实战

环境配置 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;wmsi 攻击机&#xff1a;kali2022.03 web 192.168.111.80 10.10.10.80 自定义网卡8&#xff0c;自定义网卡18 PC 192.168.111.201 10.10.10.201 自定义网卡8&#xff0c;自定义网卡18 DC 192.168.52.1…...

一个好的工程项目管理软件所包含的主要功能

工程项目管理软件哪个好&#xff1f;借助Zoho Projects强大的工程项目管理软件&#xff0c;您的团队可以在预算范围内按时交付。从质量保证到预算规划&#xff0c;Zoho Projects的工程项目管理平台旨在推动切实的成果是Zoho Projects工程项目管理软件的优势。 高质量的可交付成…...

【大数据监控】Grafana、Spark、HDFS、YARN、Hbase指标性能监控安装部署详细文档

目录Grafana简介下载软件包安装部署修改配置文件创建用户创建Systemd服务启动 GrafanaSpark应用监控 Graphite_exporterHDFS 监控YARN 监控HBase 监控Grafana 简介 Grafana 是一款开源的数据可视化工具&#xff0c;使用 Grafana 可以非常轻松的将数据转成图表(如下图)的展现形…...

面试题---CSS

面试题---CSS子绝父相下&#xff0c;子百分比的问题两栏布局问题三栏布局问题---圣杯问题(三栏&#xff0c;左右固定&#xff0c;中间自适应)。内联样式与块级样式的区别怎么让一个 div 水平垂直居中分析比较 display: none 、visibility: hidden、opacity: 0优劣和适用场景css…...

【C++】vector

目录 vector 1. vector的成员函数 1.1 构造、析构和赋值运算符重载 1.1.1 构造函数 1.1.2 析构函数 1.1.3 赋值运算符重载 1.2 迭代器 1.3 容量 1.4 元素访问 1.4.1 遍历方法 1.5 修改器 1.6 配置器 2. vector的非成员函数 vector 1. vector的成员函数 1.1 构造…...

RocketMQ安装

RocketMQ安装 安装前准备 1.RocketMQ是使用Java语言编写的所以在安装该MQ前需要Java环境。 2.准备好RocketMQ ​ RocketMQ运行版本下载地址&#xff1a; https://www.apache.org/dyn/closer.cgi?pathrocketmq/4.7.1/rocketmq-all-4.7.1-bin-release.zip ​ RocketMQ源码版…...

Spring——什么是IOC?

一、原则高内聚、低耦合二、什么是IOC&#xff1f;控制反转&#xff0c;把对象创建和对象之间的调用过程&#xff0c;交给spring进行管理三、使用IOC的目的是什么&#xff1f;降低耦合&#xff08;谁和谁的耦合&#xff1f;&#xff1f;如何降低的&#xff1f;&#xff09;原来…...

力扣(LeetCode)430. 扁平化多级双向链表(2023.03.04)

你会得到一个双链表&#xff0c;其中包含的节点有一个下一个指针、一个前一个指针和一个额外的 子指针 。这个子指针可能指向一个单独的双向链表&#xff0c;也包含这些特殊的节点。这些子列表可以有一个或多个自己的子列表&#xff0c;以此类推&#xff0c;以生成如下面的示例…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

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

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

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...