js创建对象时new关键字到底做了哪些暗操作?

先上结论:

new 大概做了如下4个步骤。
1、新建一个空白的obj对象,名字什么的都无所谓。
2、修改构造函数this的指向,使其指向新建的obj对象,并且执行该构造函数,这样就可以为新建的空白的obj对象添加上对应的属性和属性值。
3、然后再为obj添加一个__proto__属性,使其指向构造函数的prototype属性实现继承。
4、将这个对象返回出去,赋值给等号左边开发人员自己定义的对象名。

var obj = {};
Animal.call(obj);
obj.__proto__ = Animal.prototype;
return obj;

1、我们先分析第二点。修改构造函数this的指向。

  当我们有一个如下的构造函数,试想一下直接执形输出的this是什么?
  此时不要把它当成一个构造函数,任何js中的构造函数都只是一个函数(ES6 class关键字声明的类除外),直接执行没有任何问题。只是因为他的功能是为了创建对象的,我们才把函数名首字母大写并称之为构造函数,这是为了规范化。

function Animal(name){
	this.name = name;
	console.log(this);
}
Animal("cat"); //window

  答案是输出window,欸?这不对吧,如果this指向window,那么创建对象时this.name不是将name属性挂载到window上去?我们要的是将name属性挂载到新创建的对象上,显然这不符合我们的要求,既然直接执形不行,那么我们就加个new关键字,告诉游览器这个函数不是单纯的直接执行就好了呗。
  那么怎么让这个构造函数不直接执行,new添加哪一些暗操作才能创建一个对象并返回该对象呢?
  从上面分析,new 关键字创建对象时有一个暗操作必须要修改this的指向,让其指向我们新创建的对象,而不是指向window或者其他什么对象上。
  修改this的指向有挺多方式call(),apply(),bind()等等,在这里我们用call 和 apply都可以,因为我们要在修改this指向的时候立刻执行,但是bind()不会立刻执行,所以这里使用call、apply都可以。

2、接着分析第一点,创建一个空白的对象

  无论是用call()还是apply()它的第一个参数都得传入一个对象,让构造函数的this指向这个对象。同样构造方法并没有提供这个对象,既然没有那么我就自己生成一个呗。
  所以new关键字第一个暗操作应该是创建一个新的空白的对象。第二步才是修改this的指向,让this指向这个新创建的空白的对象。

var obj = {};
Animal.call(obj,"cat");

  好了此时,我们已经有一个创建的对象obj了,并且通过修改Animal的this指向,并且马上执行,Animal函数。
  这里有人可能会问了,为什么需要马上执行这个构造函数?这是为了初始化对象。
  大家可以简单理解Animal函数修改完this指向之后,变为以下形式。那么我们直接执性就可以初始化对象啦,不执行的话,光改变this指向是没有任何意义的。这也为什么改变this指向不能使用bind()的原因,因为他修改完后不会立刻执行。

var obj = {};
function Animal(obj, name){
	obj.name = name;
}

3、接下分析new第三步暗操作。

  这一步主要是为了实现原型链继承,原型链三言两语比较难讲清楚。大家知道每一个构造函数都有一个prototype属性,每一个对象都有一个__proto__属性并且指向该对象的构造函数的prototype,这么做有什么用呢?当对象上有一个变量、或者方法不存在时,他不会直接报错,他会查找它的__proto__指向的构造函数的prototype属性里是否有这个变量或者方法,有就使用它。可以简单理解prototype是为了保存这一类对象公共属性和公共方法的。
  这实际上在js __proto__属性是不可见的,他的原名也不是__proto__,而是[[Prototype]],各大游览器将其变为可见、并且改为__proto__。
  为什么要取这么复杂的名字,应该是为了不与开发人员定义的属性重名吧,不然取一个name这样常用的属性用来实现继承,开发人员一不小心就覆盖了name属性,那么他从原型链查找的时候就找不到了。所以这个属性要取的尽量复杂一些。

4、new 第四部暗操作

  当你执行完上面3步暗操作之后,不可能new出来每一个对象都叫obj吧,那么我们需要把这个对象的引用返回出去,赋值给等号左边的开发人员定义的对象名。

  以上就是new创建一个对象时,对执行构造方法创建对象的暗操作。之前看过一个博主,说过new关键字就像是一个语法糖,我觉得挺有道理的。new是为了简化这些固有、重复的代码而设置的。

5、总结

new 大概做了如下4个步骤。
1、新建一个空白的obj对象,名字什么的都无所谓。
2、修改构造函数this的指向,使其指向新建的obj对象,并且执行该构造函数,这样就可以为新建的空白的obj对象添加上对应的属性和属性值。
3、然后再为obj添加一个__proto__属性,使其指向构造函数的prototype属性实现继承。
4、将这个对象返回出去,赋值给等号左边开发人员自己定义的对象名。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vgbire

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值