起初,是神创造了天地,神说要有光,就有了光…,上帝靠着他自己的话语和能力,从无中生有,上帝到底是怎么实现的呢?这个是属于隐秘的事,我们无从得知。但是,我们在用js搬砖的过程中,哦,不!是改变世界的过程中,也经常只要一new
就能new
出来一个对象,那么这个new
的过程中发生了什么呢?今天我们就来探讨一下。
在这之前我们先简单了解一下函数和原型链
函数和构造函数
函数和构造函数有什么区别呢?
没区别(逗我玩呢?)。要说区别就是一般构造函数一般都是大驼峰命名,表明这是一个构造函数,用来new出来对象的。
函数创建时默认会有一个prototype
属性,指向一个对象,被称为函数的原型对象,原型对象默认会有一个constructor
属性,这个属性的值就是原函数。
不信请看代码:
1 | // 首先创建一个函数,并给他加一个属性name |
原型链
刚刚我们创造了一个人类的构造函数,下面我们新建一个实例:
1 | const sanpang = new Human('不知道', '独裁') |
Human
类(其实js没有类的概念,但是为了方便理解,我们就把这个构造函数,称为类)和实例之间是共享Human.prototype
这个对象的。
我们来测试一下:
1 | //首先给Human类的原型对象增加一个属性: |
那也就是说,改变了Human.prototype
,他的实例对象都会改变。这些定义在Human.prototype
上的方法和属性,称为原型方法和属性,一般是一些公用的,不需要为每个实例都赋予的属性,这样会节省一些内存开支。
对于实例方法和属性,当然是定义在构造函数上的了。比如我们一开始定义的属性interest
和age
,每个实例都会保存一份。
1 | const trunp = new Human(72, '和平') |
所以,其实类
和实例
之间并没有直接的联系,仅仅是因为共享了原型对象,如果原型对象又是另外一个类的实例,那么原型对象就共享了另一个类的原型对象,一直往上,直到对象Object
。
等等,所以new 的时候发生了什么??
new的过程
- 创建一个新的对象
- 继承或者共享构造函数的prototype对象
- 为这个新的对象添加属性(执行构造函数中的代码)
- 如果构造函数返回了一个“对象”(包括数组,函数),那么这个对象会取代整个new出来的结果。如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象
所以,我们可以模拟一下:
1 | const getClass = function (fn, ...args) { |