一篇文章让你彻底搞懂JS中的apply(不是会用,是看透本质)
问题背景(真实场景)
你是不是写过这种代码:
Math.max.apply(null, [1, 2, 3])
或者:
fn.apply(obj, args)
👉 会用,但问你一句:
❗ apply 到底“做了什么”?
❗ 为什么参数是数组?
❗ 和 call / bind 的本质差异是什么?
大多数人,到这里就模糊了。
核心问题(本质是什么)
一句话说透:
👉 apply 的本质:强行改变函数执行时的 this + 以“数组形式”传参执行函数
拆开来看就两件事:
✔ 改 this
✔ 调函数(参数是数组)
👉 就这么简单,但很多人复杂化了。
原理讲解(深入但通俗)
先看语法:
fn.apply(thisArg, argsArray)
执行时发生了什么?
👉 本质可以理解为:
thisArg.fn = fn thisArg.fn(...argsArray) delete thisArg.fn
也就是说:
👉 apply 干了 3 件事:
- 把函数“挂”到指定对象上
- 用这个对象去调用函数(改变 this)
- 删除临时属性
常见误区(很多人踩过)
误区1:apply 是“调用函数的方法”
不对。
👉 函数本来就能调用,apply 只是改变调用方式
误区2:apply 比 call 更高级
不对。
👉 唯一区别:
| 方法 | 参数形式 |
|---|---|
| call | 一个个传 |
| apply | 数组传 |
👉 本质完全一样
误区3:apply 性能更好
❗ 在现代 JS 引擎里:
👉 call / apply 几乎没差别
👉 真正影响性能的是你调用的函数逻辑
解决方案(什么时候用 apply)
场景1:参数已经是数组
function sum(a, b, c) {
return a + b + c
}
const arr = [1, 2, 3]
sum.apply(null, arr)
👉 不用解构,直接用
场景2:借用方法(this 复用)
const arrLike = {
0: 'a',
1: 'b',
length: 2
}
Array.prototype.push.apply(arrLike, ['c', 'd'])
console.log(arrLike)
// {0: 'a', 1: 'b', 2: 'c', 3: 'd', length: 4}
👉 核心能力:
❗ “让类数组用数组方法”
场景3:求最大值(经典)
const arr = [3, 5, 1] Math.max.apply(null, arr)
👉 但注意:
❗ 大数组会有栈溢出风险
现代写法:
Math.max(...arr)
工程实现(手写一个 apply)
👉 真正理解 apply,一定要自己实现一次
Function.prototype.myApply = function (context, args) {
// 处理 context
context = context || window
// 创建唯一 key,防止覆盖
const key = Symbol()
// 挂载函数
context[key] = this
// 执行函数
const result = context[key](...(args || []))
// 删除函数
delete context[key]
return result
}
测试:
function test(a, b) {
return this.x + a + b
}
const obj = { x: 10 }
console.log(test.myApply(obj, [1, 2])) // 13
👉 到这里,你已经掌握本质了
架构/设计思路(为什么 JS 要有 apply)
很多人忽略这一层 👇
👉 apply 解决的是:
❗“函数执行时的上下文控制问题”
在 JS 中:
✔ 函数 ≠ 绑定 this
✔ this 是运行时决定的
👉 apply / call 的出现:
就是为了让你显式控制 this
更深一层:
👉 JS 是函数式 + 面向对象混合语言
👉 apply 是“函数复用”的基础能力
性能与优化建议
不要滥用 apply
错误写法:
fn.apply(obj, arguments)
👉 在高频调用中,会有性能损耗
推荐写法(现代 JS)
fn.call(obj, ...arguments)
或者:
fn(...args)
注意参数长度
Math.max.apply(null, hugeArray)
👉 可能触发:
💥 Maximum call stack size exceeded
总结(认知升级)
记住这几句话就够了:
👉 apply = 改 this + 数组传参执行函数
👉 本质 = 临时挂载 + 调用 + 删除
👉 和 call 只有“参数形式”的区别
👉 是 JS 函数控制能力的核心之一
延伸思考(拉开差距)
给你几个思考题:
1️⃣ 为什么 ES6 要引入 ... 展开运算符?
👉 本质是在“替代 apply 的使用场景”
2️⃣ 为什么箭头函数不能用 apply 改 this?
👉 因为它没有自己的 this
3️⃣ Vue / React 内部是否用到 apply?
👉 大量使用(尤其是函数调用封装)
最后一刀(真正高手的理解)
👉 初级:会用 apply
👉 中级:知道 apply 改 this
👉 高级:知道它是“函数调度机制”
❗ 真正的提升:
从“怎么用”,到“为什么存在”
总结
到此这篇关于JS中apply的文章就介绍到这了,更多相关JS中apply内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
一个仿Windows UI的html table,兼容IE和firefox
兼容IE和firefox的仿Windows UI的html table2008-11-11
express-generator 配置typescript的实现步骤
本文介绍了将Express项目从JavaScript迁移到TypeScript的完整流程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2026-05-05


最新评论