在写new方法之前,我们应该先理解原型是什么?
比如:有2个对象,对象A和对象B,我希望对象A能用对象B的所有属性,这个时候就可以通过对象私有属性__proto__指向对象B,对象B就是对象A的原型
const B = {
c: 2,
d: 4
}
const A ={
a: 1,
b: 3
}
// 如果B作为A的原型
A.__proto__ = B // 尽量用Object.setPrototypeOf(A, B)去设置,该操作不规范
console.log(A)
打印A结果如下:
对象A属性[[Prototype]]即对象B,对象B
属性[[Prototype]]即Object.prototype,Object.prototype
没有
属性[[Prototype]],所以Object.prototype的原型为null
构造函数在原型方面的作用:
通过构造函数创建的每一个实例都会自动将构造函数的 prototype 属性作为其 [[Prototype]]
。
手写New方法:
function myNew(constructor, ...args) {
// 创建一个新的空对象,并将其原型链接到构造函数的原型对象
const obj = {}
Object.setPrototypeOf(obj, constructor.prototype)
// 直接用 const obj = Object.create(constructor.prototype); 可以代替上面操作
console.log(obj); // {}
// 将构造函数内部的 this 指向这个新对象
const result = constructor.apply(obj, args);
console.log(result, 'result'); // undefined
console.log(obj, 'obj'); // { name: 'Alice', age: 30 }
// 如果构造函数返回的是对象,则直接返回该对象
if (result && (typeof result === 'object')) {
return result;
}
// 否则返回这个新对象
return obj;
}
// 示例构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.getName = function() {
return this.name
}
// 使用自定义的 myNew 方法创建对象实例
const person1 = myNew(Person, 'Alice', 30);
person1.getName() // 'Alice'
constructor.apply(obj, args)
这一步,将构造函数 Person 内部的 this 指向了新创建的对象 obj,并执行构造函数内部的代码。
由于构造函数 Person 中使用了 this.name = name; 和 this.age = age; 来初始化属性,因此在这个过程中,obj 对象的属性被成功设置为 { name: 'Alice', age: 30 }。
result 输出 undefined,这是因为构造函数 Person 没有显式返回值,所以默认返回值是 undefined。