过程
function myNew(fn, ...args) {
// 1.创建一个新的对象
const obj = {};
// 2.将构造函数的prototype设置为这个对象的__proto__,
// 这样当这个对象不存在的属性或方法会顺着__proto__查找到fn.prototype
// 所以写在fn.prototype的属性或方法会被公用
obj.__proto__ = fn.prototype;
// 3.以这个对象调用函数(this就会指向这个对象)
const ret = fn.apply(obj, args);
// 4.判断返回类型。如果构造函数有返回类型且是对象,就返回那个对象,new就相当于失效了
return ret instanceof Object ? ret : obj;
}
公用属性覆盖
- 不会覆盖:执行赋值操作(f.role = { name: "f" }),是在f这个对象里加了role这个属性,所以不会影响到f2.role,f2.role依旧是f.__proto__.role
-
会覆盖:而f.role.age = 123会影响f.__proto__.role
function fun(x, y) {
this.x = x;
this.y = y;
}
fun.prototype.role = { name: "tom", age: 18 };
let f = new fun(1, 2);
let f2 = new fun(3, 4);
console.log(f.role === f2.role); //true
f.role.age = 123;
f.role = { name: "f" };
console.log(f.role); // {name: "f"}
console.log(f2.role); // {name: "tom", age: 123}
console.log(f.__proto__.role); // {name: "tom", age: 123}
Object.create()
警告: 由于现代 JavaScript 引擎优化属性访问所带来的特性的关系,更改对象的
[[Prototype]]
在各个浏览器和 JavaScript 引擎上都是一个很慢的操作。其在更改继承的性能上的影响是微妙而又广泛的,这不仅仅限于obj.__proto__ = ...
语句上的时间花费,而且可能会延伸到任何代码,那些可以访问任何[[Prototype]]
已被更改的对象的代码。如果你关心性能,你应该避免设置一个对象的[[Prototype]]
。相反,你应该使用Object.create()
来创建带有你想要的[[Prototype]]
的新对象。--- MDN