前端面试高频考点——手写new

546 阅读4分钟

引言

在JS 中,new操作符是一个非常重要的特性,它允许我们创建对象并调用构造函数来初始化这些对象。在面试中,手写new是一个非常常见的考点。本文将深入探讨new操作符的工作原理,并通过手写实现一个类似new操作符功能的函数。

56665.jpg

new操作符的作用

在JS中,使用new操作符可以创建一个新的对象,并将这个对象的原型链链接到构造函数的原型对象上。同时,它还会执行构造函数,并将构造函数中的this 绑定到新创建的对象上。这样,我们就可以通过构造函数来初始化新创建的对象的属性和方法。

例如,以下是使用new操作符创建一个Person对象的示例,来帮助我们理解new到底都干了些什么事:

function Person(name,age){
    this.name = name;
    this.age = age;
}

Person.prototype.sayName=function(){
    console.log(this.name);
}
// new 实例化运算符 
// 1. 创建一个空对象 {} 和 Person 没有血缘关系 
// {} __proto__  Object.prototype
// 2. 手动的__proto__ 指向 Person.prototype
// 3. 构造函数 this 指向 {} 执行,给{}赋值
const zzz=new Person('zzz',20);

在这个例子中,我们定义了一个构造函数Person,它接受两个参数nameage,并在构造函数内部将这两个参数赋值给新创建的对象的属性。同时,我们还在Person的原型对象上定义了一个方法sayName ,这个方法可以打印出对象的name属性。最后,我们使用new操作符创建了一个Person对象,并调用了它的sayName方法。

new操作符的工作原理

了解了new操作符的作用后,我们来深入探讨一下它的工作原理。当我们使用new操作符时,JS引擎会执行以下几个步骤:

  1. 创建一个空对象 {}
  2. 将这个新对象的原型链链接到构造函数的原型对象上
  3. 执行构造函数,并将构造函数中的this 绑定到新创建的对象上
  4. 如果构造函数返回一个非原始值(即对象或函数),则返回这个值。否则,返回新创建的对象

手写new

下面我们来手写一个new:

function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype.sayName = function () {
    console.log(this.name);
}
// 不设置形参 使用arguments 获取参数
function objectFactory() {
    // arguments 所有参数 类数组
    // console.log(arguments,arguments.length);
    const obj = new Object();  // 1. 空对象创建
    // arguments 类数组 没有shift 方法       借给 arguments shift方法
    // [].shift.call(arguments)   将类数组 转为数组 使用 shift
    const Constructor = [].shift.call(arguments)
    // console.log(Constructor);
    // 2. 手动的__proto__ 指向 Person.prototype
    obj.__proto__ = Constructor.prototype;
    // 3. this 指向 apply 第二项是数组
    const result = Constructor.apply(obj,arguments);
    // console.log(obj);
    // 4. 如果构造函数返回的是一个对象,则返回这个对象;否则返回新创建的对象
    return result instanceof Object ? result : obj;  
}
// 传参为函数名和各项值
let awei = objectFactory(Person,'zzz',20)
console.log(zzz.name);  // zzz
zzz.sayName(); // zzz

在这个实现中,我们首先创建了一个空对象obj,然后将这个对象的原型链链接到构造函数的原型对象上。接着,我们使用apply方法执行构造函数,并将构造函数中的this绑定到新创建的对象上。最后,返回对象obj

步骤分析

在上面的方法中使用到的一些方法,我会在下面做一下解释:

  1. arguments:这是一个伪数组(类数组对象), 它包含了传递给函数的所有参数。arguments 只能在函数体内访问
  2. [].shift.call(arguments)shift()定义在Array.prototype上,只能由数组使用。arguments是伪数组,没有shift()方法。我们通过一个空数组[ ]来调用shift(),并使用call()绑定到arguments上来让伪数组使用shift()方法。将函数名赋给Constructor
  3. obj.__proto__ = Constructor.prototype:将这个新对象的原型链链接到构造函数的原型对象上,保证实现new的功能
  4. Constructor.apply(obj,arguments):使用apply确定函数Constructorthis指向创建的新对象obj,将剩下的arguments作为参数一起传给函数Constructor。这里绑定this使用的是applyapply可以将所有参数用数组的方式一起传送,call只能一个一个传值。
  5. 最后,如果构造函数返回的是一个对象,则返回这个对象;否则返回新创建的对象

至此,一个简单的手写new就完成了!!!

总结

通过深入解析new操作符的机制并手写实现一个简易版本。手写new作为面试中一道常考题,希望这篇文章能够帮助到你。

sdffs.jpg