大家都常用new运算符,但是new运算符背后的原理是什么?
答:
首先new运算符后面跟的是一个构造函数,new运算符的第一个步骤就是新的对象被创建,可以理解为一个字面量对象,就是一个空对象被创建了。
它是怎么被关联到实例对象上面呢?
然后这个新的对象是继承这个构造函数的原型对象的 foo.prototype的,这一点非常重要。
这时候原型链已经被关联一部分了,就是关于原型对象已经被关联上了,但是还没有关联到最终的实例对象上。
那我们还要再看第二步,构造函数被执行,这个非常必要;
如果构造函数不执行,那么构造函数体的所有和this相关的东西都是执行不了的,这个时候上下文this会指定新实例,也就是说我们刚创建的对象要与这个this要相关联,不然的话你没有办法把这个构造函数它的上下文转到这个新实例上的话,也就是刚才创建的新对象上,你最后返回的对象没法关联。
后面有个解释,这个也是官方的解释。
如果你没有参数传入的时候,这个new foo后面加不加括号都可以。
第三步:
构造函数如果返回一个对象,那么这个对象会取代new出来的结果。
这句话怎么解释,大家想一想:
我们第一步生成了一个新对象,
第二步执行上下文要把this指向我们新创建出来的对象,
第三步我们要不要返回,就是说new运算符不是要返回一个实例嘛,我们那个实例要不要返回我们的新建对象还是个问题,什么问题呢?
那要看你这个构造函数返回的了一个对象呢,还是没有返回,还是返回其他数值类型,这个是非常关键的步骤,如果说构造函数没有返回任何返回对象,也就是说只要你这个数据类型不是对象,那么new出来的结果就是步骤一传出来的对象,也就是我们刚才创建的新对象,如果它是有返回对象的,那么我们刚才那一步就前功尽弃了,直接返回构造函数的结果。
如果没有看明白,我写一串代码,来模拟这个new运算符
/**
* 我们模拟这个先生成一个变量,我们用构造函数来写,它的参数是func,就是指定构造函数
*/
/**
* 第一步:要先生成一个新对象
* 新对象要指定Object的构造函数,比如说我们传入的func这个参数就是构造函数
* 要指定构造函数原型对象,我们使用Object.create()的方式来创建
* 也就是说我们新创建一个对象,这个对象要继承这个构造函数的原型对象
*/
/**
* 第二步:要执行构造函数
* 我们用k表示执行返回的结果,call就是用了转换上下文的,
* 我们要把上下文转换成o对象,也就是我们刚刚创建的新的对象上
*/
/**
* 第三步:要判断这个构造函数,执行完的结果是不是对象类型
* 我们用typeof来判断,如果是对象类型就直接返回k
* 如果不是就直接返回我们刚创建的对象 o
* 这样就实现new运算符的效果
*/
var new2 = function(func){
var o = Object.create(func.prototype);
var k = func.call();
}