new的原理
创建一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。
在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。
而通过这个构造函数,可以继续为原型对象添加其他属性和方法。
创建了自定义的构造函数后,其原型对象默认只会取得 constructor 属性;至于其他方法,则都从 Object 继承而来。
当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。
ECMA-262第5版管这个指针叫 [Prototype] ,脚本中没有标准的方式访问 [Prototype],但Firefox、Safari和Chrome在每个对象上都支持一个属性__proto__;而在其他实现中,这个属性对脚本是完全不可见的。
不过,要明确的真正重要的一点就是,这个连接存在于示例和构造函数的原型对象之间,而不是存在于实例和构造函数之间。
代码实现
//第一步,创建一个Animal类并给此类原型添加callName方法
function Animal(name) {
this.name = name;
}
Animal.prototype.callName = function() {
console.log(this.name)
}
//第二步,模拟new
function Mnew(fn, ...arg) {
//首先用传入的构造函数原型链创建一个对象
const obj = Object.create(fn.prototype);
//改变this指向,将该对象作为构造函数的上下文,执行构造函数,并拿到构造函数的返回值。
const ref = fn.apply(obj, arg)
//如果fn返回的是null或undefined,我们返回的是obj,否则返回ref
return ref instanceof Object ? ref : obj;
}
const cat = Mnew(Animal,'Cat')
new的具体步骤
1、创建一个空对象 改变this指向,将该对象作为构造函数的上下文,执行构造函数,并拿到构造函数的返回值。
2、 只改this指向并且把参数传递过去,call和apply都可以 根据规范,返回 null 和 undefined 不处理,依然返回obj;
3、简单来说:新建一对象,修改原型链指向构造函数和把构造函数this指向新对象并返回