震惊!手写new操作符竟如此简单 - 彻底搞懂JavaScript对象创建机制

前言

要实现手写new,关键在于先吃透它的本质。new作为 JavaScript 中创建对象的核心操作符,看似简单的语法背后,藏着一套严谨的执行逻辑。只有先弄清楚它究竟是什么------ 是连接构造函数与实例对象的桥梁 ?还是激活原型链关联的开关 ?再明确它能完成哪些核心功能------ 是初始化对象属性 ,还是建立继承关系 ?最后拆解它的执行过程中每一步都发生了什么------ 从创建空对象到绑定原型,从执行构造函数到返回实例...... 搞懂了这些,手写new的思路才会清晰起来。接下来,我们一起来揭露这个东西

new 是什么?

new是JavaScript中用于创建对象实例的关键操作符,它是面向对象编程中对象实例化的核心机制。

我们通常利用new来实例化一个对象:

js 复制代码
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.Talk = function () {
        console.log('我是' + this.name);
    }
}

// 使用new创建实例
const person1 = new Person('张三', 25);
console.log(person1); // 输出: Person { name: '张三', age: 25 }
person1.Talk(); // 输出: 我是张三

我们可以看到利用new产生的实例继承了构造函数的属性和方法,并且成功实例化了一个对象。

new 的过程中发生了什么?

当使用new调用函数时,JavaScript引擎会执行以下步骤:

  1. 创建新对象 :创建一个全新的空对象{}
  2. 链接原型 :将这个新对象的[[Prototype]](即__proto__)链接到构造函数的prototype对象
  3. 绑定this :将构造函数中的this绑定到这个新对象
  4. 执行构造函数:执行构造函数中的代码(通常用于初始化对象)
  5. 返回对象:如果构造函数没有返回对象,则自动返回这个新对象

当然,对于这5条,1,3就不用说了,

1是基础步骤,我们要返回一个实例化对象,必须得初始化一个,没有米怎么蒸米饭呢?

3的话,上一期的this指向中有讲过,传送门🚪=>美丽的地方0^0~

2,我们可以在浏览器中console.log(person1),查看它的__proto__是否等于Person.prototype

4,我们也可以随便在构造函数中加一句console.log('whatever u want'),观察它是否会执行

5,重点来咯!当构造函数显式返回一个对象时,new操作符会忽略原本创建的新对象,直接返回构造函数返回的这个对象。此时新对象的属性初始化将被丢弃,只有返回对象的内容会被保留。

构造函数返回对象完整规则:

  1. 返回对象类型(包括数组、函数等)
    → 完全替代new默认创建的对象
  2. 返回原始值(数字、字符串等)
    → 被忽略,仍然返回new创建的新对象
  3. 没有return语句
    → 正常返回new创建的新对象

示例:

js 复制代码
// 情况1:返回对象
function Case1() {
  this.a = 1;
  return { b: 2 }; // 对象优先
}
console.log(new Case1()); // { b: 2 }

// 情况2:返回原始值
function Case2() {
  this.a = 1;
  return 123; // 原始值被忽略
}
console.log(new Case2()); // { a: 1 }

// 情况3:无返回
function Case3() {
  this.a = 1;
}
console.log(new Case3()); // { a: 1 }

手写new

okk,既然我们都知道了你new出一个对象安慰自己没有对象的事实时会发生的事情了,我们开始手写一个new吧!

记住这灵魂的舞步~ :

  1. 创建新对象 :创建一个全新的空对象{}
  2. 链接原型 :将这个新对象的[[Prototype]](即__proto__)链接到构造函数的prototype对象
  3. 绑定this :将构造函数中的this绑定到这个新对象
  4. 执行构造函数:执行构造函数中的代码(通常用于初始化对象)
  5. 返回对象:如果构造函数没有返回对象,则自动返回这个新对象

ok,假设我们有一个构造函数Person,要利用我们的手写new创建一个实例,

那么首先我们要创建一个函数,用来实现new:

js 复制代码
function Person(name, age) {
    this.name = name;
    this.age = age;
}
function myNew(){}

现在我们要实现创建一个新的空对象:

js 复制代码
function myNew(){
var obj = {};
}

接下来,我们要确立原型,链接到构造函数,那么该怎么做呢?

既然我们要用到构造函数,那么我们应该至少应该拿到构造函数吧,所以我们就要把构造函数和所需要的形参传递进来!

js 复制代码
function myNew(constructor,...args){
var obj = new Object();
}
// tips: ...args为rest运算符,负责接收其余剩下的参数

接下来我们开始绑定prototype:

js 复制代码
function myNew(constructor,...args){
var obj = new Object();
obj.__proto__ = constructor.prototype;
// obj 继承构造函数的prototype,prototype包含 构造函数 的各种属性和方法
}

Next,开始激情♂地绑定this到新的实例对象上,那么怎么样能够将构造函数的this绑定到obj到上面呢?上一期我们学习了显式绑定,我们可以利用callapplybind方法来将其绑定到理想目标上:

js 复制代码
function myNew(constructor,...args){
var obj = new Object();
obj.__proto__ = constructor.prototype;
constructor.bind(obj,...args);
}

这样我们就成功了,下一步就是要执行构造函数了,我们可以用一个变量接受bind的结果并执行它:

js 复制代码
function myNew(constructor,...args){
var obj = new Object();
obj.__proto__ = constructor.prototype;
var before = constructor.bind(obj,...args);
before();
}

最后利用一个变量接受结果,判断构造函数返回的结果是否符合要求,

如果不符合则返回新对象

如果符合则返回构造函数准备好的结果

js 复制代码
function myNew(constructor,...args){
var obj = new Object();
obj.__proto__ = constructor.prototype;
var before = constructor.bind(obj,...args);
var res = before();

return typeof res === 'object' ? res || obj : obj; 
// 三目运算符,res为函数执行的结果,如果return的结果为object,则返回res,没有就返回obj
// res || obj? 这么写是因为res可能为null,而 typeof只会判断二进制前三位,
// null 和 object二进制前三位存储为0,所以判断不准
// 因此这么写当res为null时也会返回obj,只有其为object时才会返回res
}

OK,看到这里大家肯定也知道我们可以优化一部分了。我们可以把创建对象到绑定prototype 以及 从绑定this到判断结果这一段优化:

js 复制代码
function myNew(constructor,...args){
// 创建空对象,obj的__proto__继承constructor.prototype
const obj = Object.create(constructor.prototype);
// 利用apply绑定this并执行构造函数直接获得结果
const res = constructor.apply(obj, args);

return typeof res === 'object' ? res || obj : obj; 
}

总结

想要手写一个new,就要深深记住它在创建过程中会发生的事情,所以要记住以下五点!!!!!!

(我再提一提哥哥们不会烦我吧~)

  1. 创建新对象 :创建一个全新的空对象{}
  2. 链接原型 :将这个新对象的[[Prototype]](即__proto__)链接到构造函数的prototype对象
  3. 绑定this :将构造函数中的this绑定到这个新对象
  4. 执行构造函数:执行构造函数中的代码(通常用于初始化对象)
  5. 返回对象:如果构造函数没有返回对象,则自动返回这个新对象

OK就是这样,拜拜哥哥们!

相关推荐
寅时码3 分钟前
我开源了一款 Canvas “瑞士军刀”,十几种“特效与工具”开箱即用
前端·开源·canvas
CF14年老兵4 分钟前
🚀 React 面试 20 题精选:基础 + 实战 + 代码解析
前端·react.js·redux
CF14年老兵5 分钟前
2025 年每个开发人员都应该知道的 6 个 VS Code AI 工具
前端·后端·trae
十五_在努力9 分钟前
参透 JavaScript —— 彻底理解 new 操作符及手写实现
前端·javascript
典学长编程21 分钟前
前端开发(HTML,CSS,VUE,JS)从入门到精通!第四天(DOM编程和AJAX异步交互)
javascript·css·ajax·html·dom编程·异步交互
拾光拾趣录24 分钟前
🔥99%人答不全的安全链!第5问必翻车?💥
前端·面试
IH_LZH28 分钟前
kotlin小记(1)
android·java·前端·kotlin
lwlcode36 分钟前
前端大数据渲染性能优化 - 分时函数的封装
前端·javascript
Java技术小馆37 分钟前
MCP是怎么和大模型交互
前端·面试·架构
玲小珑41 分钟前
Next.js 教程系列(二十二)代码分割与打包优化
前端·next.js