当我们使用new
操作符调用函数时,背后发生了很多事情。这里是简单的new
操作符的行为:
- 创建一个新的空对象。
- 将这个空对象的原型链接到构造函数的
prototype
对象。 - 使用这个新对象作为上下文(即
this
的值)调用该构造函数。 - 如果构造函数返回一个对象,则返回这个对象;否则返回上下文。
现在,让我们尝试写一个简化版本的new
操作符,我们称之为create
:
function create(Constructor, ...args) {
// 步骤1: 创建一个新的空对象
const obj = {};
// 步骤2: 将这个空对象的原型链接到构造函数的`prototype`对象
Object.setPrototypeOf(obj, Constructor.prototype);
// 步骤3: 使用这个新对象作为上下文调用该构造函数
const result = Constructor.apply(obj, args);
// 步骤4: 如果构造函数返回一个对象,则返回这个对象;否则返回上下文
return result instanceof Object ? result : obj;
}
// 测试
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function() {
console.log(this.name);
};
const person = create(Person, "Alice", 30);
console.log(person.name); // Alice
console.log(person.age); // 30
person.sayName(); // Alice
这个create
函数是new
操作符的简化实现,它尝试模仿new
的基本行为。然而,要注意,真实的new
操作符比这个简化版要复杂得多,处理了更多的边缘情况和特性。但这个简化版本为你提供了一个对new
的基本理解。
注意: 这里的Constructor其实是外部传递过来的一个函数参数,是构造函数。将空对象obj的原型链接到Constructor.prototype构造函数的原型上
疑惑:
这个对象的原型链接到构造函数的 prototype上的意义是什么?
当你访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript 会查找该对象的原型,看是否有这个属性或方法。将这个对象的原型链接到构造函数的 prototype上意义是实现方法属性的继承。
setPrototypeOf不就是用来实现继承吗?那extends和setPrototypeOf又有什么区别?
功能很像,都用来实现继承
但是setPrototypeOf老旧,extends比较新
extends底层不是使用setPrototypeOf实现的