今天我们来聊聊 JavaScript 中那个既熟悉又神秘的 new 操作符。相信很多小伙伴在面试时都经历过这样的“名场面”面试官微微一笑推过来那个熟悉的键盘“来能不能手写一个 new 的实现”这时候如果你只是背诵了代码稍微问深一点可能就露怯了。今天我们就把这个“黑盒”拆开从底层原理到完美实现彻底搞懂它一、核心原理拆解new 到底干了啥我们在日常开发中const person new Person(Fog, 18) 写得飞起。但 new 背后到底发生了什么简单来说new 就是一个**“生产车间”**。它拿着你的图纸构造函数给你造出一个实实在在的产品实例对象。这个过程标准流程只有四步核心四步法建空房创建一个全新的空对象 {}。挂牌子将这个空对象的原型链proto链接到构造函数的原型对象prototype上。这步最关键决定了你能用这一类的公共方法。搞装修将构造函数内部的 this 指向这个新对象并执行构造函数。给对象添加属性如 name, age。交钥匙判断构造函数的返回值。如果构造函数自己返回了一个对象或函数那就以它为准否则默认返回我们在第一步创建的那个新对象。二、面试官到底在考什么面试官让你手写 new绝对不是为了看你默写代码。通过这寥寥几行代码他在考察你以下四大内功原型链的理解你知不知道实例和类是怎么关联起来的this 指向机制你懂不懂怎么用 call 或 apply 改变函数执行上下文函数参数处理面对不定参数你会用 arguments 还是 ...args边界情况处理**这是高分点**如果构造函数里写了 return你的代码还能正常工作吗三、手写进阶之路接下来我们由浅入深演示三个版本的实现。V1.0 青铜版ES5 经典写法这是最基础的写法也是很多老教材里的标准答案。我们需要处理 arguments 这个“伪数组”。JavaScriptfunction Person(name, age) { this.name name; this.age age; } Person.prototype.sayName function () { console.log(this.name); } // 核心实现 function objectFactory() { // 1. 创建一个空对象 var obj new Object(); // 2. 获取构造函数 // arguments 是类数组没有 shift 方法我们借用数组原型的 shift // 这行代码有两个作用取出第一个参数(Constructor)同时 arguments 里剩下的就是参数了 var Constructor [].shift.call(arguments); // 3. 链接原型让 obj 能访问 Person.prototype 上的属性 obj.__proto__ Constructor.prototype; // 4. 绑定 this 并执行 // 使用 apply 将 remaining arguments 传进去 var result Constructor.apply(obj, arguments); // 5. 返回值处理 // 这是一个常见的简易判断但其实有漏洞稍后在王者版揭晓 return typeof result object result ! null ? result : obj; } // 测试 var awei objectFactory(Person, 阿伟, 20); console.log(awei.name); // 阿伟 awei.sayName(); // 阿伟重点解析为什么用 [].shift.call(arguments)arguments 是一个类数组对象有 length有索引但没数组方法。通过 call我们强行让它借用了数组的 shift 方法切掉并拿到了第一个参数构造函数剩下的正好传给 apply。V2.0 黄金版ES6 现代化写法时代变了我们有了更优雅的语法糖。proto虽然好用但在生产环境中被视为非标准尽管浏览器支持性能也不如 Object.create。JavaScript// 使用 ...args 剩余参数告别 arguments function objectFactory(Constructor, ...args) { // 1. 2. 创建对象并直接链接原型 // Object.create(proto) 创建一个新对象带着指定的原型性能更好更符合规范 const obj Object.create(Constructor.prototype); // 3. 执行构造函数 const result Constructor.apply(obj, args); // 4. 返回值处理 (依然沿用旧逻辑) return typeof result object result ! null ? result : obj; }重点解析Object.create 的优势它直接创建一个已经连接好原型的对象避免了创建后再修改proto指针带来的性能损耗修改原型链在 V8 引擎中是非常昂贵的操作。V3.0 王者版无懈可击的最终版注意了如果你能写出这个版本面试官绝对会对你刮目相看。在 V1 和 V2 中我们对返回值的判断是 typeof result object。这有一个巨大的隐形漏洞如果构造函数返回的是一个 function 呢在 JS 原生 new 中如果构造函数返回函数new 表达式的结果就是那个函数。但 typeof function 是 function 而不是 object之前的代码会错误地返回 obj 实例。JavaScriptfunction objectFactory(Constructor, ...args) { // 0. 参数校验 (严谨性加分项) if (typeof Constructor ! function) { throw new TypeError(Constructor must be a function); } // 1. 创建对象链接原型 const obj Object.create(Constructor.prototype); // 2. 绑定 this 执行 const result Constructor.apply(obj, args); // 3. 完美的返回值处理关键修正 // 如果 result 是对象(非null) 或者 是函数则返回 result // 否则返回新创建的 obj const isObject typeof result object result ! null; const isFunction typeof result function; return (isObject || isFunction) ? result : obj; } // 验证特殊情况 function Factory() { return function() { console.log(I am a function); }; } const test objectFactory(Factory); console.log(typeof test); // function —— 逻辑正确四、总结你看所谓的“手写源码”其实就是对基础知识的排列组合。创建Object.create执行Function.prototype.apply判断类型检测与逻辑运算掌握了这三点new 操作符对你来说就不再是黑盒。下次面试遇到直接展示“王者版”告诉面试官我不止会写我还知道为什么要这么写。