“我不是对象,我是构造函数!”
“我不是数组,但我能遍历!”
—— JavaScript 里的两个“戏精”
如果你曾在面试中被问:“手写一个 new”,或者在控制台里对 arguments.reduce 报错一脸懵,那你不是一个人。今天我们就来揭开 JavaScript 中两场经典的 “身份冒充案” :
👉 new 是如何“造人”的?
👉 arguments 为何总想混进数组圈?
准备好了吗?泡杯咖啡,我们边笑边学 ☕️
🔨 Part 1:手写 new —— 从“空对象”到“实例化”的魔法
你以为 new Person() 只是调了个函数?错!它背后上演了一出 四幕剧:
- 出生:创建一个空对象
{}; - 认祖归宗:让这个对象的
__proto__指向Person.prototype; - 灵魂注入:把
this绑定到新对象,执行构造函数; - 命运裁决:如果构造函数返回的是对象,就用它;否则,返回新对象。
于是,我们可以手写一个 myNew,还原这场“造人仪式”:
function myNew(Constructor, ...args) {
// 1. 创建空对象,且继承构造函数的原型
const obj = Object.create(Constructor.prototype);
// 2. 执行构造函数,绑定 this
const result = Constructor.apply(obj, args);
// 3. 决定返回谁:构造函数返回的对象 or 新对象?
return (result !== null && typeof result === 'object') ? result : obj;
}
✅ 测试一下:
function Person(name) { this.name = name; }
const p = myNew(Person, '掘金小张');
console.log(p.name); // "掘金小张" ✅
💡 冷知识:
new其实不是关键字,而是一个运算符——但它干的活,比很多关键字还重!
🎭 Part 2:arguments —— 那个“长得像数组”的冒牌货
来看你写的这段经典代码(已激活):
function add() {
let sum = 0;
for (let i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
console.log(add(1, 2, 3)); // 6
看起来没问题?但如果你尝试:
// ❌ TypeError: arguments.reduce is not a function
return arguments.reduce((a, b) => a + b, 0);
Boom!💥 因为 arguments 根本不是数组!
它到底是什么?
- 是一个 类数组对象(Array-like Object)
- 有
length✅ - 能用
arguments[0]访问 ✅ - 但 没有
push、map、reduce等数组方法 ❌
📸【表情包建议】
插入一张“我看起来像程序员,但我只是穿了格子衫”的梗图,配文:“我看起来像数组,但我只是有 length。”
🔄 如何帮 arguments “转正”?
别急,JS 社会很包容,给它三条“落户通道”:
| 方法 | 代码 | 特点 |
|---|---|---|
| 展开运算符 | [...arguments] | ✨现代、简洁、推荐 |
| Array.from | Array.from(arguments) | 🧼语义清晰,可处理 iterable |
| 老派 slice | Array.prototype.slice.call(arguments) | 🕰️兼容 IE,怀旧党最爱 |
function add(...args) { // 更推荐!直接用 rest 参数
return args.reduce((a, b) => a + b, 0);
}
🎯 最佳实践:ES6 之后,请优先使用 剩余参数(
...args) !
它生下来就是真·数组,不用再“整容”或“洗白”!
🤔 为什么这些“细节”值得你死磕?
| 场景 | 价值 |
|---|---|
| 面试 | 手写 new + arguments 区别 = 基础题满分 |
| 调试 | 避免 arguments.map is not a function 这种低级报错 |
| 架构 | 理解原型链 & 动态参数机制,写出更灵活的工具函数 |
| 装X | 在 Code Review 时说:“这里用 rest 参数更语义化” 😎 |
🎬 彩蛋:JS 的“身份哲学”
JavaScript 从来不是一个“非黑即白”的语言:
- 函数是对象 ✅
- 对象可以当函数调用(如果加了
[[Call]])✅ - 数组是对象 ✅
null的typeof是"object"(历史 bug)😅
所以,arguments 想当数组,new 想造对象——
不是它们疯了,是 JS 本来就这么自由!
✅ 总结:记住这两句话
new不是魔法,是四步流程;arguments不是数组,但你可以让它变成。
下次再有人问你:“JS 里最像数组又不是数组的是谁?”
你可以微微一笑:“是我,arguments,正在申请 Array 户口。” 👮♂️📄