类与构造函数
在javascript中,类就是构造函数的升级版,写起来更简单。原本写在构造函数中的内容,对应写在了类中的constructor里。而且如下图所示,原本写在构造函数的prototype(对prototype的介绍在下面)上的方法,直接写在了类的里面。
类的类型也是function,所以也有prototype属性。它们的作用就是实例化实例,说成人话就是自动化工厂生产产品。类和构造函数都扮演自动化工厂的角色
实例与实例化
如下图,a就是构造函数A的实例,let a = new A()
的过程,就叫实例化
同理,类也是一样。如下图,f就是类F的实例,let f = new F()
的过程,就叫实例化
原型与原型链
什么是原型?
原型也叫原型对象。每个函数都有prototype属性(普通对象没有prototype属性,如上图f.prototype的结果是undefined),这个属性的类型是对象,我们给它起了个名字叫原型对象,简称原型。
什么是原型链?
依然看上面2张图,a.__proto__ == A.prototype
这种相等就是原型链的本质,它连接了a和A。
那这个等式怎么理解呢?记住:每一个对象(函数和数组本质上也是对象)都有 __proto__属性,它指向该对象的构造函数的原型对象(prototype)
原型的作用是什么?
当我们在构造函数的原型中添加方法时,通过该构造函数实例化出来的所有实例都可以使用该方法。一处添加多处使用
没有它行不行?
没有它,我们只能将需要添加的方法放在全局下面,这样做可能造成全局污染。而且这个方法只属于这个构造函数,其他地方根本不会用到,将它添加在全局下面也别扭。
实例化当中的原型链
再此看最上面的2张实例化的图,一张是构造函数的,一张是类的。图中的a.__proto__ == A.prototype
和 f.__proto__ == F.prototype
就是原型链最直观的样子
构造函数的继承
如下图所示,构造函数D继承自构造函数A。temp函数只是一个临时函数,用来传递A的prototype给D。如果不用这个临时函数,直接D.prototype = new A()
也可以,只是new A()会多占用一块空间(这里不考虑A里是空的情况,正常使用当中一般不会是空的),而new temp()因为temp里是空的所以不会占用多余空间。
类的继承
类的继承有关键字extends,直接用就好了。原理参考构造函数的继承。
继承中的原型链
在上面关于构造函数继承的介绍的图里,我们设置了D.__proto__ = A.prototype
,这和实例化是一致的,目的是使D本身能够使用A.prototype上的全部方法。此外我们还设置了 D.prototype = new temp()
(本质上是D.prototype = new A()
上面也介绍了不直接用new A()的原因)。这里其实我们想实现的目标只有一个,那就是让D的实例也能使用A.prototype上的全部方法。所以我们要想办法将A.prototype的内容传递给D.prototype,但是我们又不能直接写D.prototype = A.prototype,因为这样的话一旦我们操作D.prototype,A.prototype也会随之改变。所以我们将D.prototype指向A的实例,也就是new A()。因为A的实例含有A.prototype上的所有方法,而且当我们想要操作D.prototype时也不会影响到A.prototype。
关于类的继承中的原型链,原理也是如此。