在 ES5 的时候,我们经常使用 new
操作符来调用函数从而创建一个对象,这时候,函数被称为对象的构造函数,一般函数名的首字母需要大写,那么 new
到底做了什么神奇的事情,能够让函数在不返回任何值的情况下, 返回一个对象,并且该对象还是构造函数内部的 this
呢?不要走开,本文将把这些谜底一一揭晓!
new 的4件事
new
操作符在构造函数内部主要做了4件事:
- 首先会创建一个空对象 —
newObject
- 将对象的
__proto__
属性指向构造函数的prototype
属性 - 将构造函数的
this
指向新对象 - 判断构造函数的返回值类型,如果返回的是非原始值,那么就作为
new
操作符的最终结果,否则就是newObject
作为new
操作符的最终结果。
实现原理
了解清楚 new
做了哪些事情之后,我们就来马上实现一下 new
的原理吧!
function myNew() {
const constructorFn = Array.prototype.shift.call(arguments);
// 判断参数是否是一个函数
if (typeof constructorFn !== "function") {
console.error("type error");
return;
}
// 新建一个空对象,对象的__proto__指向构造函数的prototype (第1步和第2步)
const newObject = Object.create(constructorFn.prototype);
// 将 this 指向新建对象,并执行函数 (第3步)
const result = constructorFn.apply(newObject, arguments);
// 如果构造函数返回的对象,则返回该值。(第4步)
const typeResult = typeof result
if (typeResult !== 'null' && (typeResult === "object" || typeResult === "function")) {
return result;
}
// 否则返回新对象 (第4步)
return newObject;
}
// 使用方法
function User(name, age) {
this.name = name;
this.age = age;
}
User.prototype.introduce = function () {
return `My name is ${this.name}, ${this.age} years old.`;
};
const user1 = myNew(User, 'jack', 18);
console.log(user1); // {name: 'jack', age: 18}
console.log(user1.introduce()) // My name is jack, 18 years old.
实际上,new
的4件事对应了3行代码,就是上面源代码标注的第1步,第2步,第3步和第4步,所以总的来说,我们实现 new
的原理只需要3行代码!