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

JavaScript重定义this指向(apply、call、bind)

一、apply()在JavaScript中apply()是函数的原型方法Function.prototype.apply用于调用一个函数并显式指定该函数内部的this值同时以数组或类数组对象的形式传入参数。基本语法func.apply(thisArg,[argsArray]);func要调用的函数。thisArg在函数执行时绑定到this的对象。如果传null或undefined在非严格模式下this指向全局对象浏览器中是windowNode.js 中是global严格模式下为null。[argsArray]一个数组或类数组对象如arguments、NodeList其元素将作为参数依次传给函数。如果不需要传参可传[]或null/undefined。返回值被调用函数的返回值。核心作用改变函数内部的this指向。以数组形式传递参数。经典示例借用数组方法最常见用途。// 类数组对象有length和索引但不是Array。constarrayLike{0:a,1:b,2:c,length:3};// 借用Array.prototype.slice方法。constrealArrayArray.prototype.slice.apply(arrayLike);console.log(realArray);// [a, b, c]。现代写法可用Array.from(arrayLike)但apply在旧代码中很常见。求最大值/最小值配合Math。constnumbers[5,6,2,8,1];// Math.max接收多个参数不接受数组。// Math.max(numbers) → NaN。// 使用apply展开数组。constmaxMath.max.apply(null,numbers);constminMath.min.apply(null,numbers);console.log(max);// 8。console.log(min);// 1。ES6可用扩展运算符替代Math.max(...numbers)。改变this上下文。constperson{name:Alice};functiongreet(greeting,punctuation){return${greeting},${this.name}${punctuation};}// 使用apply调用greet指定this为person参数以数组传入。constresultgreet.apply(person,[Hello,!]);console.log(result);// Hello, Alice!。继承中调用父类构造函数ES5写法。functionAnimal(name){this.namename;}functionDog(name,breed){// 调用父类构造函数绑定this到当前实例。Animal.apply(this,[name]);this.breedbreed;}constdognewDog(Buddy,Golden Retriever);console.log(dog.name);// Buddy。console.log(dog.breed);// Golden Retriever。ES6可用super(name)替代。applyvscallvsbind方法参数形式是否立即执行返回值func.apply(thisArg, [arg1, arg2, ...])数组/类数组是函数执行结果func.call(thisArg, arg1, arg2, ...)逐个列出是函数执行结果func.bind(thisArg, arg1, arg2, ...)逐个列出可部分预设否新函数绑定后的greet.apply(person,[Hi,.]);// Hi, Alice.。greet.call(person,Hi,.);// Hi, Alice.。constboundGreetgreet.bind(person,Hi);boundGreet(.);// Hi, Alice.。二、call()在JavaScript中call()是函数的原型方法Function.prototype.call用于立即调用一个函数并显式指定该函数内部的this值同时以逐个参数的形式传入参数。它和apply()非常相似核心区别只在于参数的传递方式。基本语法func.call(thisArg,arg1,arg2,...,argN);func要调用的函数。thisArg函数执行时绑定到this的对象。若为null或undefined非严格模式 →this指向全局对象浏览器中是window。严格模式 →this就是null。arg1, arg2, ...逐个列出的参数不是数组。返回值被调用函数的返回值。核心作用改变函数内部的this指向。以“展开”的形式传参与apply的数组形式相对。经典示例借用其他对象的方法。constobj1{name:Alice,greet:function(greeting){return${greeting}, Im${this.name};}};constobj2{name:Bob};// 让 obj1.greet 在obj2的上下文中执行。constresultobj1.greet.call(obj2,Hello);console.log(result);// Hello, Im Bob。这里this指向了obj2所以this.name是Bob。将类数组转为真数组配合Array.prototype.slice。functiondemo(){// arguments是类数组。constargsArrayArray.prototype.slice.call(arguments);console.log(argsArray);// [1, 2, 3]。}demo(1,2,3);现代写法Array.from(arguments)或[...arguments]但需注意arguments不是真正的可迭代对象在某些环境下需谨慎。检查数据类型利用Object.prototype.toString。functiongetType(value){returnObject.prototype.toString.call(value).slice(8,-1);/* 若不加“.slice(8, -1)”进行切分输出结果如下 [object Array] [object Date] [object Null] */}console.log(getType([]));// Array。console.log(getType(newDate()));// Date。console.log(getType(null));// Null。这是判断JS数据类型的最可靠方法之一因为call能确保toString在目标值上正确执行。继承ES5写法。functionAnimal(name){this.namename;}functionDog(name,breed){// 调用父构造函数绑定this到当前实例。Animal.call(this,name);this.breedbreed;}constdognewDog(Max,Labrador);console.log(dog.name);// Max。console.log(dog.breed);// Labrador。ES6可用classsuper()替代。callvsapplyvsbind方法参数形式是否立即执行返回值func.call(thisArg, arg1, arg2, ...)逐个参数是函数执行结果func.apply(thisArg, [argsArray])数组/类数组是函数执行结果func.bind(thisArg, arg1, arg2, ...)逐个参数可预设否新函数functiongreet(a,b){return${a}${this.name}${b};}constperson{name:Tom};greet.call(person,Hi,!);// Hi Tom !。greet.apply(person,[Hi,!]);// Hi Tom !。constboundgreet.bind(person,Hi);bound(!);// Hi Tom !。三、bind()在JavaScript中bind()是函数的原型方法Function.prototype.bind用于创建一个新函数绑定函数该新函数在被调用时永久绑定指定的this值。可预设部分参数称为“柯里化”或“部分应用”。bind()不会立即执行原函数而是返回一个绑定了上下文和参数的新函数。基本语法constnewFuncfunc.bind(thisArg,arg1,arg2,...);func原始函数。thisArg新函数执行时内部this指向的对象。arg1, arg2, ...可选预设的参数会填充到新函数参数的前面。返回值一个全新的函数。核心特性永久绑定this不可再被call/apply覆盖。constperson{name:Alice};functiongreet(){returnHello,${this.name};}constboundGreetgreet.bind(person);console.log(boundGreet());// Hello, Alice。// 即使用call/apply也无法改变this。console.log(boundGreet.call({name:Bob}));// 仍然是Hello, Alice一旦用bind绑定this就永久固定了。支持预设参数部分应用 / 柯里化。functionmultiply(a,b){returna*b;}// 预设第一个参数为 2constdoublemultiply.bind(null,2);console.log(double(5));// 10 (2 * 5)console.log(double(10));// 20 (2 * 10)也可以预设多个参数functionadd(a,b,c){returnabc;}constaddFiveAndTenadd.bind(null,5,10);console.log(addFiveAndTen(3));// 18 (5 10 3)经典使用场景解决回调函数中this丢失问题。classTimer{constructor(){this.seconds0;}start(){// 问题setTimeout 中的回调函数this指向window非严格模式。// setTimeout(function() {// this.seconds; // 报错或无效。// }, 1000);// 解决方案用bind绑定this。setTimeout(function(){this.seconds;console.log(this.seconds);}.bind(this),1000);}}consttimernewTimer();timer.start();// 正常输出1。现代写法更推荐用箭头函数自动继承外层thissetTimeout((){this.seconds;},1000);事件监听器中保持上下文。classButton{constructor(element){this.elementelement;this.clickCount0;// 绑定this确保handleClick中的this指向当前实例。this.element.addEventListener(click,this.handleClick.bind(this));}handleClick(){this.clickCount;console.log(Clicked${this.clickCount}times);}}若不用bindhandleClick被调用时this会指向elementDOM元素导致错误。创建专用函数函数工厂functionlog(level,message){console.log([${level}]${message});}consterrorLoglog.bind(null,ERROR);constinfoLoglog.bind(null,INFO);errorLog(Something went wrong);// [ERROR] Something went wronginfoLog(Process started);// [INFO] Process startedbindvscallvsapply方法是否立即执行参数形式主要用途func.bind(thisArg, ...args)否逐个参数创建绑定后的新函数用于回调、事件等。func.call(thisArg, arg1, arg2, ...)是逐个参数立即调用临时指定this。func.apply(thisArg, [args])是数组立即调用参数以数组传入。注意事项bind返回的是新函数原函数不变。多次bind只有第一次生效constffunction(){returnthis.value;};constgf.bind({value:1});consthg.bind({value:2});console.log(h());// 1不是 2绑定函数的length属性会变化functionfn(a,b,c){}console.log(fn.length);// 3。console.log(fn.bind(null,1).length);// 2已预设1个参数。对bind返回的新函数使用new关键字创建实例letfoo{value:1,};functionPerson(name,age){this.namename;this.ageage;console.log(this.name);console.log(this.age);console.log(this.value);}Person.prototype.getNamefunction(){returnthis.name;};letPerPerson.bind(foo,xiaoming);Per(18);// 输出xiaoming 18 1。console.log(foo.name);// 输出xiaoming。console.log(foo.age);// 输出18。console.log(foo.value);// 输出1。letpernewPer(18);// 输出xiaoming 18 undefined。console.log(per.getName());// 输出xiaoming。console.log(foo.name);// 输出xiaoming。console.log(foo.age);// 输出18。console.log(foo.value);// 输出1。// 由上述结果可知对bind方法返回的绑定对象的函数使用new关键字创建实例时原绑定的对象在创建的实例中会失效。

相关文章:

JavaScript重定义this指向(apply、call、bind)

一、apply() 在JavaScript中,apply()是函数的原型方法(Function.prototype.apply),用于调用一个函数,并显式指定该函数内部的this值,同时以数组(或类数组对象)的形式传入参数。基本语…...

智慧教育+虚拟仿真:解锁煤矿专业实训新范式

煤炭作为我国主体能源,行业安全生产与智能化转型对高素质技术技能人才提出迫切需求,职业院校煤矿专业迎来发展新机遇的同时,也面临着实训教学与行业需求精准对接的挑战。煤矿安全意识警示教育与防治实训室的建设,正是以新一代信息…...

06|AI 参与开发的安全底线:别把密钥和隐私喂进去

本篇目标:这是“卷 0”的最后一篇。在正式开始写代码前,我们必须立下“生死状”。遵守这些规则,能让你免于牢狱之灾或破产风险。一、血淋淋的教训 在你觉得“我只是个小透明,黑客不会搞我”之前,先看两个真实案例&…...

网络安全学习路线:2026年最新技术趋势与系统化成长路径

【值得收藏】网络安全学习路线:2026年最新技术趋势与系统化成长路径 这篇文章为网络安全学习者提供了一条系统化的六阶段学习路径,从基础准备到专业深耕。文章介绍了三大发展方向、2026年新趋势与热点,并提供科学学习方法和职业发展建议。强…...

书单号视频搬运软件推荐8款(2026实测版)

书单号视频搬运软件推荐(2026实测版) 做书单号搬运/二剪,核心要抓去重过原创、批量效率、配音字幕三点,以下按“新手易上手→专业高效率→专用工具”分级推荐,附适用场景与关键技巧。 一、新手首选(手机端&…...

企业培训ROI怎么算?这套可直接套用的量化表,让效果看得见

做企业培训的人,几乎都遇过这样的灵魂拷问:“花了十几万做培训,到底给公司带来了什么?”“课上大家听得很认真,怎么业绩没见涨?”“明年培训预算要砍30%,你拿什么证明这笔钱花得值?”…...

库克推最便宜MacBook,为啥还是会被骂?

这些年,苹果的产品可以说是价格越来越高,面对着高价的诟病,苹果终于下定决心推出廉价产品,这就是最新款的MacBook,然而就是这一款平价产品却反而遭到了消费者的诟病,这到底是怎么回事?一、库克推…...

洛谷 P1455 搭配购买

题目描述明天就是母亲节了,电脑组的小朋友们在忙碌的课业之余挖空心思想着该送什么礼物来表达自己的心意呢?听说在某个网站上有卖云朵的,小朋友们决定一同前往去看看这种神奇的商品,这个店里有 n 朵云,云朵已经被老板编…...

2026 年上海本地靠谱财税公司榜单,服务口碑双在线

2026年,上海本地财税公司逐渐增多,服务质量和口碑备受关注。本文将盘点几家凭借专业服务和良好信誉脱颖而出的财税公司。这些公司在财税筹划、账务处理等领域表现突出,客户普遍评价其响应速度快、服务透明,成为企业发展的得力助手…...

新建虚拟机

新建虚拟机1、2、3、4、5、6、7、8、改虚拟机配置9、10、11、12、改为自己的光驱确定即可,然后开启虚拟机14、15、16、安装位置,已选择自动分区,点击“完成”即可17、软件选择,选“GNOME”桌面,点击“完成”18、命名完…...

苹果新款笔记本电脑发布:性能升级与市场定位调整

新款 MacBook 处理器升级亮点多 新款 MacBook Pro 搭载的 M5 Pro 和 M5 Max 处理器备受瞩目,不仅让苹果最快的笔记本电脑处理器速度显著提升,其内部还进行了重大改进。这两款处理器的升级,无疑为 MacBook Pro 带来了更强大的性能表现&#xf…...

基于 NXP iMX8MP ARM平台安装测试 Openclaw

By Toradex秦海 1). 简介 Openclaw AI agent 开源项目最新非常火热,目前主流是基于 Mac 或者 X68 PC 进行安装部署,本文就尝试基于 NXP iMX8MP ARM 平台通过 Docker 环境进行部署测试。另外,通过 Docker 部署的好处除了可复用性&#xff0c…...

安心部署 OpenClaw,数美科技智能体安全防护方案来了!

近期,开源AI智能体OpenClaw爆火,在GitHub上短短几周便成为有史以来最受欢迎的开源项目,引领AI正式迈入“Agent时代”。这股狂潮在中国市场引发了前所未有的部署热,不仅腾讯云、百度等大厂纷纷下场提供部署服务,各地方政…...

MFC CDialog触摸屏长按不响应右键消息解决方案

方案1 重写虚函数GetGestureStatus,返回0即可。方案2 响应WM_TABLET_QUERYSYSTEMGESTURESTATUS消息,返回0即可。方案3 用vs2010之前的版本编译,vs2010开始默认CWnd类出于性能原因返回TABLET_DISABLE_PRESSANDHOLD。注意:如果子窗口…...

在 Linux 上通过命令行上架 iOS APP,Fastlane + AppUploader(开心上架)

很多团队的 CI 或发布环境运行在 Linux 服务器上,例如 GitLab Runner、Jenkins 或自建构建节点。当应用已经生成 .ipa 文件之后,接下来就是是否可以在 Linux 上直接把 IPA 上传到 App Store? 答案是可以的,关键在于把流程分开&…...

【转行必看】程序员从零转行大模型全攻略:从入门到职业落地无坑指南

人工智能浪潮下,大模型技术的爆发彻底重塑了科技行业的人才需求版图。以GPT、BERT、LLaMA为代表的主流大模型,不仅在自然语言处理、计算机视觉等核心领域实现颠覆性突破,更催生出一大批高薪岗位。 对普通程序员而言,转行大模型绝…...

搅拌功率计算避坑指南:挡板设置对永田公式影响的7个关键点

搅拌功率计算避坑指南:挡板设置对永田公式影响的7个关键点 在搅拌工艺的研发与优化中,功率计算是绕不开的核心环节。许多工程师都熟悉永田进治公式,它结构清晰,是估算搅拌功率的经典起点。然而,公式本身只是一个数学模…...

ChatGPT Prompt Engineering实战:开发者代码运行环境全解析

背景痛点:你的代码究竟在哪儿跑? 最近在折腾ChatGPT的Prompt Engineering,我发现很多开发者朋友,包括我自己一开始,都踩过一个坑:搞不清Prompt处理代码到底在哪里执行。 这听起来像是个低级问题&#xff…...

C++三种参数传递方式:从交换函数看值、指针与引用的区别

本篇文章将通过一个简单的交换函数示例&#xff0c;详细介绍C中的三种参数传递方式&#xff1a;值传递、指针传递和引用传递。我们会分析每种方式的特点以及它们在函数调用中对实参的影响。代码预览#include <iostream> using namespace std;// 1. 值传递 void Swap01(in…...

NX二次开发C#-----NXopen测量两个面的投影距离

该代码实现了一个计算两个面之间投影距离的方法。通过创建工作部件中的测量距离构建器&#xff0c;设置投影方向为指定向量&#xff0c;并指定两个测量面对象。使用最小投影距离算法创建测量对象&#xff0c;最终返回两个面之间的投影距离值。计算完成后销毁测量构建器以释放资…...

Linux下HYM8563 RTC驱动加载失败的5种排查姿势(附i2cdetect实战)

Linux下RTC驱动加载失败&#xff1a;从硬件到内核的深度排查实战指南 最近在调试一块嵌入式板卡时&#xff0c;遇到了一个典型的RTC驱动加载问题&#xff1a;系统启动时HYM8563 RTC芯片驱动加载失败&#xff0c;但重启后却能正常工作。这种“开机失败、重启正常”的现象在嵌入式…...

【图像隐藏】基于分数随机小波变换和密码分析的图像隐写术附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f447; 关注我领取海量matlab电子书和…...

整合物联网、大数据、人工智能等技术的Java智慧工地项目管理系统源码

系统功能1、项目人员管理项目管理&#xff1a;项目名称、施工单位名称、项目地址、项目地址、总造价、总面积、施工准可证、开工日期、计划竣工日期、项目状态等。人员信息管理&#xff1a;支持身份证及人脸信息采集&#xff1b;基础信息、证书信息、合同信息、培训信息等多项数…...

Qt 实现三维坐标系的方法

使用 Qt 实现三维坐标系通常需要结合 Qt 3D 模块或第三方库&#xff08;如 OpenGL&#xff09;。以下是几种常见方法&#xff1a;使用 Qt 3D 模块Qt 3D 提供了完整的 3D 渲染框架&#xff0c;适合创建交互式 3D 应用。以下是基本实现步骤&#xff1a;#include <Qt3DCore/QEn…...

mcp-server-chart的跨域问题

mcp-server-chart本地源码部署完成后&#xff0c;SSE模式启动 mcp-server-chart --transport sse --host 0.0.0.0后&#xff0c;可以访问http://localhost:1122/sse&#xff0c;一直显示不出来tools,F12进行调试显示CORS跨域错误。对sse.ts进行了更改。import type { Server } …...

从本地到云端:若依前后端分离项目部署全流程(附跨域配置与宝塔面板实战)

从本地到云端&#xff1a;若依前后端分离项目部署全流程&#xff08;附跨域配置与宝塔面板实战&#xff09; 最近和几个技术团队的朋友聊天&#xff0c;发现不少人在做项目交付时&#xff0c;总在部署环节卡壳。尤其是像若依这类功能完善但结构相对复杂的开源框架&#xff0c;从…...

告别手动调整!WPS 2019 JS宏一键统一公文格式(含避坑指南)

告别手动调整&#xff01;WPS 2019 JS宏一键统一公文格式&#xff08;含避坑指南&#xff09; 你是否也曾被一份格式混乱的公文文档折磨得焦头烂额&#xff1f;从上级单位或网络下载的文件&#xff0c;字体五花八门&#xff0c;页边距随心所欲&#xff0c;页码位置飘忽不定&…...

LangGraph 实战笔记:用 AI 发起流程应用

&#x1f4d2; LangGraph 实战笔记&#xff1a;用 AI 发起流程应用 一句话总结&#xff1a;LangGraph 让 AI 从“直线思维”变成“闭环思维”&#xff0c;是实现复杂、可循环、人机协同工作流的首选工具。 目录 一、核心概念&#xff08;无代码版&#xff09;二、LangGraph vs…...

多层FPC叠层设计中阻抗失配故障分析

在FPC设计圈&#xff0c;一直流传着一句话&#xff1a;“单层拼弯折&#xff0c;多层拼阻抗”。相比结构简单的双层FPC&#xff0c;多层FPC的设计难点&#xff0c;90%都集中在叠层结构引发的阻抗失配问题上&#xff0c;而每一次阻抗失配&#xff0c;都会直接引发信号完整性故障…...

ESP32多传感器环境监测终端设计与实现

1. 项目概述“基于ESP32的超级大杂烩”是一款面向嵌入式环境监测应用的高集成度便携式终端设备。其核心设计目标是在极小物理尺寸&#xff08;49.2 mm 37 mm 37 mm&#xff09;约束下&#xff0c;实现多维度环境参数的高可靠性采集、本地化智能分析、多样化人机交互与低功耗持…...