在学习这篇博文前,请先移步个人另一篇博文:JS 一张图理解prototype、proto和constructor的关系,先弄清楚“原型链”,这样对于理解继承会很是有效。
注意:博文中提到的“属性”,指的是“属性+方法”,这里统称为“属性”;html
1、构造函数继承
var obj = new Object(); 使用构造函数new一个对象实例(因此程序员每天都在谈对象,哈哈哈)程序员
特色:app
- 实例对象继承父类的共有属性和私有属性
来个实例加深理解:
function Animal() { this.type = '动物'; } Animal.prototype.getType = function(){ console.log(this.type); } let animal = new Animal(); console.log(animal.type); // 动物 animal.getType(); // 动物
2、原型链继承
Child.prototype = new Parent(); 将父类的实例做为子类的原型ssh
特色:函数
- 子类的prototype上的全部属性将被彻底覆盖,因此子类的prototype属性应该在覆盖后从新定义;
- 子类的constructor指向父类,为了构造函数的完整性,须要从新指定子类的constructor属性,方法:Child.prototype.constructor = Child;
- 修改子类与父类同名的属性,不会修改父类的属性;这是由于父类的属性在子类的原型链上,且这些属性至关因而子类的__prototype__或者更加上一级。(这里若是理解不了,说明没理解透 JS 一张图理解prototype、proto和constructor的关系 这篇文章)
原型继承,并非把父类的属性和方法COPY一份给子类,而是让子类的原型和父类原型之间搭建一个连接的桥梁,之后子类(或者子类的实例),能够经过原型链的查找机制,找到父类原型上的方法,从而调取这些方法使用便可。
来个实例加深理解:
function Animal() { this.type = '动物'; } Animal.prototype.getType = function(){ console.log(this.type); } function Cat(){ this.vary = '猫'; } Cat.prototype.getVary = function(){ console.log(this.vary); } Cat.prototype = new Animal(); var cat = new Cat(); // cat.getVary() // 报错:cat.getVary is not a function [缘由:Cat.prototype = new Animal()的操做覆盖了原型链] console.log(cat.constructor); // Animal 这个constructor实质调用的是Animal.prototype.constructor // 修改Cat类的constructor为Cat Cat.prototype.constructor = Cat; console.log(cat.constructor); // Cat cat.getType(); // 动物 // 修改Cat类prototype上的getType方法,看是否影响Animal类的getType方法 Cat.prototype.getType = function(){ console.log('我是猫科类'); } var animal = new Animal(); animal.getType(); // 动物
3、call、apply、bind继承
在子类的构造体中,使用call、apply、bind方法,让父类方法中的this指向子类的实例,也就是改变this的上下文环境。学习
特色:this
- 子类构造体继承父类的私有属性(继承完成后,子类和父类是不要紧的)
先来个call实现原理,很重要的哦
Function.prototype.call2 = function () { var ary = [...arguments].slice(1); if (!arguments[0]) { this(...ary); } else { var obj = Object(arguments[0]); // 将参数变成一个对象 obj.__proto__.fn = this; obj.fn(...ary); delete obj.__proto__.fn; } };
来个实例加深理解:
function Animal() { this.type = '动物'; } Animal.prototype.getType = function(){ console.log(this.type); } function Cat(){ Animal.call(this); this.vary = '猫'; } Cat.prototype.getVary = function(){ console.log(this.vary); } var cat = new Cat(); console.log(cat.type); // 动物 // cat.getType(); // Uncaught TypeError: cat.getType is not a function cat.type = '猫科动物'; var animal = new Animal(); console.log(animal.type); // 动物
4、寄生组合继承
var child = Object.create(obj, props); url
- obj:一个对象,应该是新建立的对象的原型。
- props:可选。该参数对象是一组属性与值,该对象的属性名称将是新建立的对象的属性名称,值是属性描述符
我先来一段Object.create的实现方式(看懂原理很重要)spa
Object.create = function (o) { var F = function () {}; F.prototype = o; return new F(); };
咱们这里只分析参数obj的骚操做,能够看出来,Object.create是内部定义一个对象,而且让F.prototype对象赋值为引进的对象/函数 o,并return出一个对象的实例。.net
只要看懂了原理,咱们能够参考“原型链继承”的方式去理解这种继承方法;
来个实例加深理解:
function Animal() { this.type = '动物'; } Animal.prototype.getType = function(){ console.log(this.type); } var cat = Object.create(new Animal(), { vary: { value: '猫科动物' } }); console.log(cat.constructor); // Animal 这个constructor实质调用的是Animal.prototype.constructor console.log(cat.type); // 动物 cat.getType(); // 动物 console.log(cat.vary); // '猫科动物'