1. 原型链继承
原型链继承:想要继承,就必须要提供父类(继承谁,提供继承的属性)
//父级
function Person(name) { //给构造函数添加参数
this.name = name;
this.age = 10;
this.sum = function (){
console.log(this.name)
}
}
//原型链继承
function Per() {
}
Per.prototype = new Person(); //主要 实现继承
var per1 = new Per();
console.log(per1.age); //10
重点:让新实例的原型等于父类的实例 特点:1.实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!) 缺点: 1>新实例无法向父类构造函数参数。 2>父子构造函数的原型对象之间有共享问题
2. 借用构造函数继承
使用call和apply借用其他构造函数的成员, 可以解决给父构造函数传递参数的问题, 但是获取不到父构造函数原型上的成员.也不存在共享问题
//父级
function Person(name) { //给构造函数添加参数
this.name = name;
this.age = 10;
this.sum = function (){
console.log(this.name)
}
}
//子构造函数
function Per(name) {
//使用call借用Person的构造函数
Person.call(this,name)
}
//测试是否有了Person的成员
var stn = new Per('我是');
stn.sum(); // 我是
console.log(stn.age)
重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制)) 缺点:1、只能继承父类构造函数的属性。 2、无法实现构造函数的复用。(每次用每次都要重新调用) 3、每个新实例都有父类构造函数的副本,臃肿。 特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。 2、解决了原型链继承缺点1、2、3。 3、可以继承多个构造函数属性(call多个)。 4、在子实例中可向父实例传参。
3. 组合继承
借用构造函数 + 原型式继承
//父级
function Person(name) { //给构造函数添加参数
this.name = name;
this.age = 10;
this.sum = function (){
console.log(this.name)
}
}
//创建子构造函数
function Per(name) {
Person.call(this,name); //借用构造函数
}
Per.prototype = new Person() //继承原型链继承
var str = new Per('zhao');
console.log(str.name); //'zhao' 是继承了Per子构造函数的属性
console.log(str.age); // 10 是继承了Person父类原型的属性
重点:结合了两种模式的优点,传参和复用 特点:1、可以继承父类原型上的属性,可以传参,可复用。 2、每个新实例引入的构造函数属性是私有的。 缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数
4. 原型链继承
//父级
function Person(name) { //给构造函数添加参数
this.name = name;
this.age = 10;
this.sum = function (){
console.log(this.name)
}
}
//设置父构建函数的原型
Person.prototype.fn = function (){
console.log(this.age)
}
//构建子构造函数
function Per() {
}
//实现继承
var str = new Person(); //拿到父类的实例
console.log(str.age); // 10
str.fn(); 10
重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。 特点:类似于复制一个对象,用函数来包装。 缺点:1、所有实例都会继承原型上的属性。 2、无法实现复用。(新实例属性都是后面添加的)
5. 寄生式继承
//父级
function Person(name) { //给构造函数添加参数
function fn(){}
fn.prototype = name; //继承传入的参数
return new fn(); //返回函数对象
}
var str = new Person();
//以上是原型式继承,给原型式继承在套一个壳子传递参数
function Per(name) {
var fn1 = Person(name);
fn1.name = "zhao";
return fn1
}
var fn3 = Per(str);
console.log(fn3.name); //返回str对象,继承了str的属性
重点:就是给原型式继承外面套了个壳子。 优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。 缺点:没用到原型,无法复用
6. 寄生组合式继承
function Person(name){
this.name = name;
this.hobbies = ['a','b','v']
};
function student(name,age){
Person.call(this,name);
this.age = age;
}
//关键的三步 实现继承
// 使用F空函数当子类和父类的媒介 是为了防止修改子类的原型对象影响到父类的原型对象
let fn = function (){};
fn.prototype = Person.prototype;
student.prototype = new fn();
var fn1 = new student('zhao','24')
console.log(fn1)
组合继承最大的缺点是最调用两次父构造函数 一次是设置子类实例的原型的时候:
student.prototype = new Person();
一次是在创建子类型实例的时候:
var fn = new student('zhao','24')
7. es6实现继承
class parents {
constructor(){
this.grandmather = 'rose';
this.grandfather = 'jack';
}
}
class children extends parents{
constructor(mather,father){
//super 关键字,它在这里表示父类的构造函数,用来新建父类的 this 对象。
super();
this.mather = mather;
this.father = father;
}
}
let child = new children('mama','baba');
console.log(child)