单纯用来当笔记用,不喜勿喷。也欢迎大家指出有错的地方。
第一种:借用构造函数继承
基本思想:子类的构造函数内部调用了父类型构造函数。说白了就是通过使用apply()和call()方法在新创建的对象上执行父类构造函数。
function Parents() { this.age = [50, 52];}function Son() { //继承了Parents Parents.call(this);}console.log(new Son())
在 * 行通过call方法借调了父类型的构造方法。
同时需要注意的是通过构造方法的继承实际上是在新创建的Son实例的环境下调用了Parent构造方法,这样的好处就是每个Son的实例都有自己的属性的副本。
function Parents() { this.age = [50, 52];}function Son() { //继承了Parents Parents.call(this);}let firstSon = new Son();firstSon.age.push(25);console.log(firstSon.age); // [50, 52, 25]let secondSon = new Son();console.log(secondSon.age); // [50, 52]
劣势:
-
方法都在构造函数中定义,无法达到函数复用。
-
子类无法查看到父类的原型中定义的方法。
function Parents() { this.age = [50, 52];}function Son() { //继承了Parents Parents.call(this);}let firstSon = new Son();firstSon.age.push(25);console.log(firstSon.age); // [50, 52, 25]Parents.prototype.loveSon = function() { console.log(true)}let papa = new Parents();papa.loveSon(); // truefirstSon.loveSon(); // Uncaught TypeError: firstSon.loveSon is not a function
第二种:原型链继承
**基本思想:**利用原型链让一个引用类型去继承另一个引用类型的属性和方法。
function Parents() { this.parentsName = '父母的名字'}Parents.prototype.getParentsName = function() { return this.parentsName}function Son() { this.sonName = '儿子的名字'}Son.prototype = new Parents(); *Son.prototype.getSonName = function() { return this.sonName}let firstSon = new Son();console.log(firstSon.getParentsName())
Parents 和 Son 类型分别有自己的属性和方法。通过创建 Parents 的实例,并将该实例赋值给Son.prototype实现原型链继承。
劣势:
-
不能使用对象字面量创建原型方法,因为这样会重写原型链。
function Parents() { this.parentsName = '父母的名字'}Parents.prototype.getParentsName = function() { return this.parentsName}function Son() { this.sonName = '儿子的名字'}Son.prototype = new Parents();Son.prototype = { getSonName : function() { return this.sonName }}let firstSon = new Son();console.log(firstSon.getParentsName()) // Uncaught TypeError: firstSon.getParentsName is not a function -
包含引用类型值的原型属性会被所有的实例所共享。
function Parents() { this.ages = [50, 52];}function Son() {}Son.prototype = new Parents();let firstSon = new Son();firstSon.ages.push(25);console.log(firstSon.ages); // [50, 52, 25]let secondSon = new Son();console.log(secondSon.ages) // [50, 52, 25]
第三种:组合继承(原型链+构造函数)
**基本思想:**使用原型链实现对原型属性和方法的继承,再通过借用构造函数来实现对实例属性的继承。
function Parents() { this.ages = [50, 52]; this.parentsName = '父母的名字';}Parents.prototype.sayParentName = function() { console.log(this.parentsName)}function Son() { //继承属性 Parents.call(this); //第一次调用父类Parents() this.sonName = '儿子的名字';}//继承方法Son.prototype = new Parents(); //第二次调用父类Parents()Son.prototype.sayAge = function() { console.log(this.ages)}let firstSon = new Son();console.log(firstSon)
组合继承结合了构造函数继承和原型继承的优点。既可以继承父类原型的内容,也不会造成原型里属性的修改。
劣势:
- 调用两次父类的构造函数。
第四种:原型式继承
基本思想:借助原型可以基于已有的对象创建新对象。
function createObj(obj) { function Func() { } Func.prototype = obj; return new Func();}
这种方式也可以通过Object.create() 方法实现。
第五种:寄生式继承
基本思想: 创建一个用于封装继承的函数,在函数内部以某种方式增强这个对象,最后返回这个对象
function createObj(obj) { //调用函数创建一个新对象 let objClone = Object.create(obj); //以某种方式增强这个新对象 objClone.sayHello = function() { console.log('Hello') } //返回这个对象 return objClone;}
劣势:
- 每次创建对象都要创建一次方法。
- 无法复用。
六:寄生组合继承
基本思想:寄生式继承、原型链继承和构造继承组合体
function Parents(name) { this.name = name; this.ages = [50, 52];}Parents.prototype.getParentsName = function() { console.log(this.name)}function Son(name, age) { //继承属性 Parents.call(this, name); this.age = age;}//寄生式继承let Func = function() {};Func.prototype = Parents.prototype;//原型链继承Son.prototype = new Func();let child = new Son('zcw', 25);console.log(child)