阅读视图

发现新文章,点击刷新页面。

为什么有的函数要用 call,有的却完全不用?

——从 this 设计本质理解 JavaScript 方法分类

在学习 JavaScript 的过程中,很多人都会卡在一个问题上:

为什么 Object.getPrototypeOf(obj) 不需要 call
Object.prototype.toString 却必须用 call

更进一步的问题是:

我怎么提前知道一个函数到底是“参数型函数”还是“this 型函数”?

本文将从设计层面而不是“记规则”的角度,彻底解释这个问题。


一、困惑的根源:我们混淆了两种“函数设计方式”

在 JS 里,函数只有一种语法形式,但实际上有两种完全不同的设计思路

1️⃣ 参数型函数(Parameter-based)

Object.getPrototypeOf(obj)
Object.keys(obj)
Math.max(1, 2, 3)

特点:

  • 操作对象 通过参数传入
  • 函数内部 不依赖 this
  • this 是谁 无关紧要

2️⃣ this 型函数(This-based)

obj.toString()
arr.push(1)
Object.prototype.toString.call(value)

特点:

  • 操作对象 来自 this
  • 函数内部 强依赖 this
  • 必须明确 this 指向谁

👉 是否需要使用 call,只取决于这一点


二、为什么 Object.getPrototypeOf 不需要 call?

先看调用方式:

Object.getPrototypeOf(left)

它的“设计意图”非常明确:

  • 要操作的对象是 left
  • left 已经作为参数传入
  • 函数内部只关心参数,不关心 this

可以把它理解为伪代码:

function getPrototypeOf(obj) {
  return obj.__proto__
}

👉 这是一个纯工具函数(utility function)

所以:

  • 不需要 call
  • call 反而多余

三、为什么 Object.prototype.toString 必须用 call?

再看这个经典写法:

Object.prototype.toString.call(value)

为什么不能直接这样?

Object.prototype.toString(value) // ❌

因为这个方法的设计是:

  • 没有参数
  • 要检查的对象只能来自 this

伪代码理解:

Object.prototype.toString = function () {
  return "[object " + 内部类型(this) + "]"
}

👉 如果你不告诉它 this 是谁,它根本不知道要检查什么。

这就是 必须使用 call 的根本原因


四、一个极其重要的判断标准(80% 准确)

看方法“挂在哪里”

✅ 挂在构造函数本身上的(参数型)

Object.keys
Object.getPrototypeOf
Array.isArray
Math.max

特点:

  • Object.xxx
  • Array.xxx
  • Math.xxx

👉 几乎一定是参数型函数


✅ 挂在 prototype 上的(this 型)

Object.prototype.toString
Array.prototype.push
Array.prototype.slice
Function.prototype.call

特点:

  • xxx.prototype.xxx
  • 操作“当前对象”

👉 几乎一定依赖 this


口诀总结(非常重要)

静态方法用参数,原型方法靠 this


五、最可靠的方法:一行代码验证

如果你真的不确定,直接用这一招。

验证是否依赖 this

const fn = Object.prototype.toString
fn() // ❌ 报错或结果异常

👉 没有 this 就不能工作 → this 型函数


验证是否依赖参数

const fn = Object.getPrototypeOf
fn({}) // ✅ 正常执行

👉 this 不重要 → 参数型函数


六、为什么不能“所有函数都用 call”?

技术上可以,但语义上是错误的

Object.getPrototypeOf.call(null, obj)

问题在于:

  • this 被完全忽略
  • 代码可读性变差
  • 违背 JS API 的设计初衷

👉 call 的存在是为了解决 this,而不是统一写法


七、总结一句话(博客结尾版)

JS 中是否使用 call
不取决于“函数高级不高级”,
只取决于“这个函数是否依赖 this”。


八、你现在卡住,其实非常正常

你现在遇到的不是“语法问题”,而是:

从“会用 JS” → “理解 JS 设计” 的过渡阶段

这是一个所有中高级 JS 开发者都必经的坎。

❌