面试中我们经常会被问道new
操作符的原理,有时候有笔试的时候,可能还要手写实现,今天我们就一起来简单实现一下。
首先,我们需要直到new
的过程中发生了什么?我们通过一个例子看一下:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function() {
console.log('i am ' + this.name);
};
const p = new Person('jack', 18);
console.log(p); // output: {name: 'jack', age: 18}
p.say(); // output: i am jack
可以看到,new
操作会返回一个新的对象,新的对象会继承函数Person
的属性和Person
的原型上的方法;接下来,我们来模拟实现一下:
// new操作符 手写模拟实现
// 1、返回一个新对象;
// 2、新对象继承构造函数的属性, 即新对象的__proto__ 等于 构造函数的prototype;
// 3、构造函数有返回值的情况,值类型和引用类型的判断;
function new1() {
// 创建一个新对象,最后return出去
let obj = {};
// 利用数组的shift方法取到第一个参数;shift方法可以操作类数组的数据,并返回删除的第一条数据,即传入的构造函数
const constructor = [].shift.call(arguments)
// 使实例的__proto__指向构造函数的prototype
obj.__proto__ = constructor.prototype;
// 使构造函数的this指向这个新对象(也就是构造函数的实例)
const ret = constructor.apply(obj, arguments);
// 这里有个判断,如果构造函数有返回值时,判断返回值是不是对象类型,如果是则返回,如果不是则把obj返回;
return typeof ret === 'object' ? ret : obj
}
我们再用之前的例子测试一下:
// 没有返回值的情况
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function() {
console.log('i am ' + this.name);
};
const p = new1(Person, 'jack', 18);
console.log(p); // output: {name: 'jack', age: 18}
p.say(); // output: i am jack
// 有返回值的情况
function Person(name, age) {
this.name = name;
this.age = age;
return {
name,
sex: 'male'
}
}
const p = new1(Person, 'jack', 18);
console.log(p); // output: {name: 'jack', sex: 'male'}
经验证,我们模拟的new1
方法能简单实现new
操作符的结果。