function Parent() {
this.name = 'parent';
this.say = function () {
console.log('hello,' + this.name);
};
}
function Child() {}
Child.prototype = new Parent();
const c = new Child();
const p = new Parent();
console.log(c.name); // 'parent'
多重继承
function A() {
this.a = 11;
}
function B() {
this.b = 22;
}
function C() {
A.call(this);
B.call(this);
}
C.prototype = Object.create(A.prototype);
C.prototype.constructor = C;
// 合并B的prototype
Object.assigin(C.prototype, B.prototype);
const c = new C();
往往在项目中都会看到有用
class
,或者OOP
思想去组织业务代码,本篇只做项目中常用到的继承以及对不同继承方式的回顾,也是再次加深对继承的一些理解,希望你在项目中有些帮助和思考。正文开始...
构造函数
我们通过构造函数构建对象
我们通过
new 构造函数()
方式新建了两个对象tigger
、cat
,其实我们会发现,相当于有多少对象,我就要实例化多少个对象。并且实例化的对象都相互独立,互不影响。现在我想trigger
与cat
拥有同样的属性或者方法呢?可以利用原型链
prototype
共享方法,当使用
new Animal('cat')
或者new Animal('tigger')
,你会发现同样的事情,我们实例化了多次,因为这样做,tigger
与cat
并不相等,那么如何可减少内存开销呢。我们可以利用
单件模式
一个全局变量去处理,举个例子或者在构造函数上绑定一个静态属性,这样比定义全局变量要好得多,推荐下面这种方式
但是这样我们会发现
const trigger = new Animal('trigger')
实际上无论实例化多少个,都只会返回首次实例化的对象,对于不同场景还是得特殊处理。自定义一个数组,完全继承
数组
所有特性constructor
查找对象的构造函数
判断
print
的构造函数是不是Print
也可以用这个来代替
原型继承法
所有对象共享一个原型对象,基于构建器工作模式,将父类的
prototype
直接赋值给子类的prototype
从打印里我们可以看出,子类可以访问父类
prototype
上的属性或者prototype
方法,但是父类自身属性
或者自身方法
不能访问,但是,我们注意到如果子类prototype
属性有父类相同的prototype
属性名时,此时子类会覆盖父类prototype
的属性。子类自身属性与父类自身属性同名时,此时子类访问就会有值,访问的是自身属性,c.ParentName
打印就会是888
于此同时子类
prototype
修改会同时修改父类的prototype
临时构造器
现在我有一个需求,子类只继承父类的
prototype
,不需要继承父类自身本身的属性,举个栗子佐证下我们可以发现实际上利用
extends
方法,利用了一个中间的F
构造函数,通过F.prototype = Parent.prototype
,然后将Child.prototype = new F()
,与上面原型继承不同的是,修改子类prototype
与父类相同的属性时,并不会修改父类prototype
的属性。本质上就是借鸡生蛋,借用了F
的prototype
,不直接修改父类的prototype
原型属性拷贝继承
将父类的
prototype
属性值拷贝给子类注意,只会继承父类
prototype
属性,父类自身属性并不会继承,因此这种与临时构造器
功能上如出一辙,子类并不能修改父类自身的属性。寄生继承
这种继承本质上仍然是用利用父类的
prototype
赋值给了一个中间构造函数F
的prototype
,他的弊端是并不能访问父类的自身属性与自身方法, 但是child.__protototype__.age
会修改父类的prototype
上的同名属性。构造函数继承,利用 call 继承【构造器继承】
我们注意到
c.age
返回的是undefined
,因为age
不是构造函数本身的属性或者方法,在构造函数prototype
的方法或者属性无法访问,如果我需要访问呢?我们就加了一行代码实现了
Child.prototype = Object.create(Parent.prototype)
,这种方式子类与父类的耦合非常低,子类修改与父类同名prototype
的属性并不会影响父类。原型链继承
实际上还有一种更简单的继承,让子类的
prototype
等于父类的实例
,也称为原型链
继承多重继承
extends 继承
注意
constructor
中有super()
调用构造函数的变体,es6 的 class
引入
utils.js
总结
1、
obj instanceof A
判断一个对象的构造函数(A 是否是 obj 的构造函数),如果是则返回true
、不是返回false
2、
A.prototype.isPrototypeOf(obj)
判断构造函数A
是不是obj
实例对象的构造函数3、常用的几种继承、
原型继承法
、临时构造器
、原型属性拷贝继承
、寄生继承
、构造器继承【call】
、原型链继承
、extends继承
4、call
父类构造函数在子类构造函数调用call
实现继承,父类除了了自身属性和自身方法能被继承访问,父类原型的方法子类无法访问5、
Child.prototype = Object.create(Parent.prototype)
实现继承父类