7.实现继承的几种方式以及他们的优缺点
①类式继承(构造函数)
var father = function() {
this.age = 52;
this.say = function() {
alert('hello i am '+ this.name ' and i am '+this.age + 'years old');
}
}
var child = function() {
this.name = 'bill';
father.call(this);
}
var man = new child();
man.say();
特点就是创建子类实例时,可以向父类传递参数,可以实现多继承(call多个父类对象)
缺点:
-
实例并不是父类的实例,只是子类的实例
-
只能继承父类的实例属性和方法,不能继承原型属性/方法
-
无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
②组合式继承(伪经典继承)
将 原型链继承
和 经典继承
组合。使用原型链继承方式实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又保证每个实例都有各自的属性。
SuperType.prototype.greet = function() {
return 'hello~,' + this.card.name;
}
•
function SuperType(gender) {
this.card = {
name: '佩奇',
age: 20,
gender: gender
}
}
优点如上
不足:无论在什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部
③原型式继承
两种方法:
一、借用构造函数(本质上就是做了一次浅复制)
借用构造函数,在一个函数内部创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。
二、使用Object.create() ES5通过增加Object.create()方法,将原型式继承的概念规范化了
// 借用构造函数
function helperFun(targetObj) {
function newFun() {}
newFun.prototype = targetObj;
return new newFun();
}
•
let myObj = {
username: 'dog',
age: 14,
other: {
hobby: 'reading',
taste: 'sore'
}
}
•
console.log(myObj);
let newObj = helperFun(myObj)
newObj.username = 'cat';
newObj.other.hobby = 'sleeping';
console.log(newObj);
--------------------------------------------------------
// Object.create()
let presentIbj = {
username: '熊大',
sex: 'male',
age: 19,
greet() {
console.log('name is ' + this.username);
}
}
•
let newObj1 = Object.create(presentIbj);
let newObj2 = Object.create(presentIbj);
newObj1.username = '熊二';
console.log(newObj1);
console.log(newObj2);
④寄生式继承
寄生式继承就是创建一个仅用于封装继承过程的函数,该函数在内部以某种方式(使用原型式继承对一个目标对象进行浅复制,增强这个浅复制的能力)来增强对象,最后就好像像真的是它做了所有工作一样返回对象。引用类型的属性始终会被继承和共享。
/ 寄生式继承 function helperFun(targetObj) { function newFun() {}; newFun.prototype = targetObj; return new newFun(); } function packInherit(originObj) { let evalObj = helperFun(originObj); evalObj.greet = function() { console.log('hello~,' + this.name); }; return evalObj; } let initObj = { name: '虹猫', like: ['reading', 'running'], age: 20 } let newObj1 = packInherit(initObj); console.log(newObj1); //[ 'reading', 'running', '蓝兔' ] newObj1.like.push("蓝兔"); console.log(newObj1.like); //[ 'reading', 'running', '蓝兔' ] newObj1.greet(); //hello~,虹猫 let newObj2 = packInherit(initObj); newObj2.name = '蓝兔'; console.log(newObj2); //{ greet: [Function (anonymous)], name: '蓝兔' } newObj2.greet(); //hello~,蓝兔 console.log(newObj2.like); //[ 'reading', 'running', '蓝兔' ]
优点就是:上手简单,无需单独创建构造函数。
缺点就是:函数复用率降低。
⑤寄生组合式继承
寄生组合继承是为降低父类构造函数的开销。通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
// 寄生组合式 Super.prototype.say = function() { console.log(this.name); } function Super(name) { this.name = name, this.colors = ['red', 'blue', 'green'] } function Son(name, age) { this.age = age; Super.call(this, name) } var another = Object.create(Super.prototype); another.constructor = Son; var another = Object.assign(Son.prototype(), Super.prototype()) // Son.prototype = another; var instance1 = new Son('duck', 19) instance1. instance1.colors.push('pink') var instance2 = new Son('cat', 18)
优点就是:只调用一次父构造函数,并且避免了在子原型上添加不必要,多余的属性。与此同时,原型链还能保持不变
缺点就是:代码太复杂
⑥class语法继承
// class继承 class Parent { constructor(name, gender) { this.name = name; this.gender = gender; this.greet = function() { console.log('greet'); }; } speak() { console.log("parent speak") } static speak() { console.log("static speak") } } //class 子类 extends 父类 class Son extends Parent { //在子类的构造方法中调用父类的构造方法 constructor(name, gender, hobby) { super(name, gender); this.hobby = hobby; } //子类中声明的方法名和父类中的方法名相同时,子类中的方法将覆盖继承于父类的方法 speak() { console.log("Son speak"); } } const grandson = new Son('lucky', 'male', 'reading'); console.log(grandson.name, grandson.gender, grandson.hobby); //lucky male reading grandson.greet(); //greet grandson.speak(); //Son speak Son.speak(); //static speak
标签:function,构造函数,console,name,继承,优缺点,几种,js,log From: https://www.cnblogs.com/alwaysrun/p/17177913.html