搞懂 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 规范中这样写: this 关键字执行为当前执行环境的 ThisBinding。 MDN 上这样写: 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] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。 示例 1…...
【mysql是怎样运行的】-InnoDB数据页结构
文章目录1. 数据库的存储结构:页1.1 磁盘与内存交互基本单位:页1.2 页结构概述1.3 页的上层结构2. 页的内部结构2.1 第1部分:文件头部和文件尾部2.1.1 File Header(文件头部)(38字节)2.1.2 File…...
VIM实用指南(10)语法自动补全插件coc.nvim
最近发现了一个新的自动补全插件coc.nvim异步,nodejs后端,配合它自身的lsp支持用起来非常舒服,同样也支持lsp和snippets,强烈推荐,值得一试。 1、使用vimplug安装插件 1.进入coc.nvim 在github的主页https://github.…...
【Vue3 第二十二章】过渡动画
一、基本用法 <Transition> 是一个内置组件,这意味着它在任意别的组件中都可以被使用,无需注册。它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。进入或离开可以由以下的条件之一触发: 由 v-if 所触发的切换由 v-…...
【linux】:进程状态(僵尸进程等)以及环境变量
文章目录 前言一.进程状态 进程的优先级二.环境变量总结前言 本篇文章是接着上一篇【linux】:进程概念的后续,对于有基础的同学可以直接看这篇文章,对于初学者来说强烈建议大家从上一篇的概念开始看起,上一篇主要解释了冯诺依曼体系以及操…...
【C语言——练习题】指针,你真的学会了吗?
✨✨✨✨如果文章对你有帮助记得点赞收藏关注哦!!✨✨✨✨ 文章目录✨✨✨✨如果文章对你有帮助记得点赞收藏关注哦!!✨✨✨✨一维数组练习题:字符数组练习题:字符指针练习题:二维数组练习题&am…...
Linux用户空间与内核空间通信(Netlink通信机制)
一,什么是Netlink通信机制 Netlink是linux提供的用于内核和用户态进程之间的通信方式。但是注意虽然Netlink主要用于用户空间和内核空间的通信,但是也能用于用户空间的两个进程通信。只是进程间通信有其他很多方式,一般不用Netlink。除非需要…...
3.3日报
今天写技术文档 跟需求对其 找负责人要上游数据接口,并处理更新时间问题 遇到的问题: 1.调用上游接口,需要token,而我的数据看板是不需要登录的,需要其他途径获取token 不同数据使用的接口不在一个项目中ÿ…...
并发编程-进程
并发编程-进程 进程创建启动 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文档: http://doc.autoxjs.com/ NO14. AutoJs6项目文档:https://github.com/SuperMonster003/AutoJs6 NO…...
红日(vulnstack)2 内网渗透ATTCK实战
环境配置 链接:百度网盘 请输入提取码 提取码:wmsi 攻击机:kali2022.03 web 192.168.111.80 10.10.10.80 自定义网卡8,自定义网卡18 PC 192.168.111.201 10.10.10.201 自定义网卡8,自定义网卡18 DC 192.168.52.1…...
一个好的工程项目管理软件所包含的主要功能
工程项目管理软件哪个好?借助Zoho Projects强大的工程项目管理软件,您的团队可以在预算范围内按时交付。从质量保证到预算规划,Zoho Projects的工程项目管理平台旨在推动切实的成果是Zoho Projects工程项目管理软件的优势。 高质量的可交付成…...
【大数据监控】Grafana、Spark、HDFS、YARN、Hbase指标性能监控安装部署详细文档
目录Grafana简介下载软件包安装部署修改配置文件创建用户创建Systemd服务启动 GrafanaSpark应用监控 Graphite_exporterHDFS 监控YARN 监控HBase 监控Grafana 简介 Grafana 是一款开源的数据可视化工具,使用 Grafana 可以非常轻松的将数据转成图表(如下图)的展现形…...
面试题---CSS
面试题---CSS子绝父相下,子百分比的问题两栏布局问题三栏布局问题---圣杯问题(三栏,左右固定,中间自适应)。内联样式与块级样式的区别怎么让一个 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运行版本下载地址: https://www.apache.org/dyn/closer.cgi?pathrocketmq/4.7.1/rocketmq-all-4.7.1-bin-release.zip RocketMQ源码版…...
Spring——什么是IOC?
一、原则高内聚、低耦合二、什么是IOC?控制反转,把对象创建和对象之间的调用过程,交给spring进行管理三、使用IOC的目的是什么?降低耦合(谁和谁的耦合??如何降低的?)原来…...
力扣(LeetCode)430. 扁平化多级双向链表(2023.03.04)
你会得到一个双链表,其中包含的节点有一个下一个指针、一个前一个指针和一个额外的 子指针 。这个子指针可能指向一个单独的双向链表,也包含这些特殊的节点。这些子列表可以有一个或多个自己的子列表,以此类推,以生成如下面的示例…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...
