原型、继承
原型
在规范里,prototype 被定义为:给其它对象提供共享属性的对象。
JS是通过函数来模拟类,当我们创建一个函数的时候,js会给这个函数自动添加prototype属性,值是一个包含constructor属性的对象,不是空对象。当我们把函数当成构造函数通过new关键词调用的时候,js会帮我们创建该构造函数的实例,实例继承构造函数prototype的所以属性和方法(实例通过设置自己的__proto__
指向构造函数的prototype来实现继承)
constructor
constructor属性也是对象所独有的,它是一个对象指向一个函数,这个函数就是该对象的构造函数。
所有 object 对象都有一个隐式引用
什么叫隐式引用?
所谓的隐式,是指不是由开发者(你和我)亲自创建/操作。__proto__
原型链
原型链的概念,仅仅是在原型这个概念基础上所作的直接推论。
既然 prototype 只是恰好作为另一个对象的隐式引用的普通对象。那么,它也是对象,也符合一个对象的基本特征。
也就是说,prototype 对象也有自己的隐式引用,有自己的 prototype 对象。
如此,构成了对象的原型的原型的原型的链条,直到某个对象的隐式引用为 null,整个链条终止。
继承
所谓的原型继承,就是指设置某个对象为另一个对象的原型(塞进该对象的隐式引用位置)。
在 JavaScript 中,有两类原型继承的方式:显式继承和隐式继承。
显式原型继承
所谓的显式原型继承,就是指我们亲自将某个对象设置为另一个对象的原型。
通过调用Object.setPrototypeOf 方法
1 |
|
还有另一种途径。即是通过 Object.create 方法,直接继承另一个对象。
Object.setPropertyOf 和 Object.create 的差别在于:
- 1)Object.setPropertyOf,给我两个对象,我把其中一个设置为另一个的原型。
- 2)Object.create,给我一个对象,它将作为我创建的新对象的原型。
隐式原型继承
通过 new 去创建 user 对象,可以通过 user.consturctor 访问到它的构造函数。
函数对象和普通对象
通过字面量或构造函数new的方式来创建对象
将对象分为函数对象和普通对象,所谓的函数对象,其实就是 JavaScript 的用函数来模拟的类实现
ES5 中的继承实现方法
new 关键字
手写new
1 |
|
- 创建一个空对象
- 将该对象的隐式原型指向构造函数的显式原型
- 使用call改变this指向
- 如果无返回值或者返回值是非对象,则返回这个新建的obj,否则直接返回该返回值对象。
继承的多种方式和优缺点
1、原型链继承
1 |
|
存在问题:
- 1、引用类型得属性被所有实例共享
- 2、在创建Child实例得时候,不能向Parent传参
2、借用构造函数(经典继承)
1 |
|
优点:
- 1、避免了引用类型的属性被所有实例共享
- 2、可以在Child中向Parent传参缺点:
1
2
3
4
5
6
7
8function Parent(name) {
this.name = name
}
function Child(name) {
Parent.call(this, name)
}
var child = new Child('YoLin')
child.name // YoLin
方法都在构造函数中定义,每次创建实例都会创建一遍方法
3、组合继承
原型链继承和经典继承的结合
1 |
|
优点:融合原型链继承和构造函数继承的优点,是javascript中最常用的继承模式
组合继承最大的缺点是会调用两次父构造函数。
- 一次是设置子类型实例的原型时
- 一次在创建子类型实例的时候
4、原型式继承
1 |
|
就是 ES5 Object.create 的模拟实现,将传入的对象作为创建的对象的原型。
缺点:包含引用类型的属性始终都会共享相应的值
5、寄生式继承
创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象。
1 |
|
缺点:跟借用构造函数模式一样,每次创建对象都会创建一遍方法。
6、寄生组合式继承
为了避免重复调用父构造函数
1 |
|
将组合式继承中的
1 |
|
变成调用object重新创建一个新的Parent的原型实例,并赋值给Child的prototype来实现
1 |
|
这种方式的高效率体现它只调用了一次 Parent 构造函数,并且因此避免了在 Parent.prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用 instanceof 和 isPrototypeOf。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!