手写new:揭开new的神秘面纱,手撕面试手写题

242 阅读4分钟

当我们使用构造函数直接创建一个新的对象时,只需要new一下就好了。但从未停下思考为什么new一下就好了? new究竟是什么?这是在面试中常考的一道手写题,今天就让我们来揭开它的面纱。

在正式手写new之前,我们先要认识下 new 是什么。

new 是什么?

new 是JS中的一个实例化运算符,用于创建一个用户定义的构造函数的实例或内置构造函数的实例。

new的工作流程

使用 new 关键字调用函数时,该函数被视作构造函数,并且执行特定的操作来创建和初始化新对象。

1.创建新对象

当你使用 new 运算符调用一个构造函数(例如Person()),JS的V8引擎会创建一个新的空对象 {}。这个空对象将作为返回的对象,它包含在构造函数中设置的所有属性和方法。

2.设置原型链

接下来,JS的引擎将会将新对象的内部链接[[Prototype]](可以通过__proto__访问)连接到构造函数的prototype属性上,使得新对象可以调用构造函数原型上的属性和方法。这也是JS能实现继承的关键。

function Car() {} console.log(new Car().__proto__ === Car.prototype); // true
3.绑定this

然后,构造函数上的this关键字会被绑定到新创建的对象上,这样构造函数可以随时向新对象添加属性和方法,或者进行修改。this关键字会指向正在创建的对象实例。

function Car(make) {
    this.make = make; // 'this' 指向新创建的对象
}
const myCar = new Car('Toyota');
console.log(myCar.make); // 输出: Toyota
4.执行构造函数

此时,构造函数的主体代码被执行。构造函数可以执行任意的初始化逻辑,包括但不限于定义属性、调用其他方法或进行复杂的计算。这些操作都是在这个新对象的上下文中完成的。

5.返回对象

最后,如果构造函数没有显式返回对象类型的值(即null或任何对象),那么new表达式的结果就是新创建的对象。如果构造函数确实返回了一个对象,则返回的是构造函数中指定的对象而不是新创建的对象。

function Car() {
    return {}; // 显式返回一个对象,将会覆盖新创建的对象
}

const myCar = new Car();
console.log(myCar instanceof Car); // false, 因为返回的是一个普通对象

以上就是用new关键字来调用构造函数来创建实例对象的详细过程。 接下来让我们来手写一个new来巩固一下。

手写new

  1. 先来定义一个构造函数Person
function Person(name,age){
    this.name = name;
    this.age = age;
}

Person.prototype.sayName = function(){
    console.log(this.name);
}  

在这个构造函数中,我们定义了它的属性nameage,并在原型对象(Person.prototype)上创建了sayname方法。

  1. 再定义objectFactory函数来模仿new关键字的功能。
function objectFactory(){
    console.log(arguments,arguments.length);
const obj = new Object();
const Constructor =[].shift.call(arguments);
 console.log(Constructor);
 obj.__proto__ = Constructor.prototype;
 Constructor.apply(obj,arguments);
 console.log(obj);
 return obj;
}

让我们仔细分析下:

  • 首先将传入的参数和数量全部打印出来,有助于后期进行调试。
  • 然后用new Object()方法来创建一个新的空对象obj
  • 再用[].shift.call(arguments)来移除并返回第一个参数,即构造函数并打印出来。因为arguments是一个类数组对象,不能直接调用shift方法,需要用[].shift.call()方法让arguments借用数组的shift方法。
  • 设置新对象的原型链,把新对象的原型设置成构造函数obj上的prototype,确保继承关系成功建立起来。
  • 使用apply方法来执行构造函数,同时将this绑定到新对象上,并传递其余参数。
  • 最后就是打印出构建好的对象,检查是否正确,再返回。

3.创建一个实例对象来检查,这里我们创建一个awei来检查一下。

let awei = objectFactory(Person,'awei',18)
console.log(awei.name);
awei.sayName();

objectFactory()会接收Person构造函数、'awei'18作为参数,然后模仿new来创建awei这个实例对象。 Snipaste_2024-12-17_16-46-12.png 从结果来看,我们成功模仿new的底层运行机制,手写出一个new出来并成功创建了一个实例对象。

小结

通过手写new,我们发现new在创建一个实例对象时:

  • 首先是利用引擎创建一个空的对象来接收参数。
  • 将新对象的内部原型指向构造函数的原型属性。
  • 再将this指向新的对象。
  • 执行构造函数代码。
  • 返回构建好的对象。如果没有返回对象,则返回上面创建出的对象。 手写new对理解JavaScript中对象创建机制十分有帮助。在阅读本文后,想必能轻松拿捏面试中的手写题。