1.通过原型链继承
function ExpOne(age) {
this.age = age || 20;
this.nameArr = [ 'Tom', 'Cat' ];
}
ExpOne.prototype.say = function() {
console.log(this.age);
console.log(this.nameArr);
};
let expOne = new ExpOne(18);
expOne.say(); //18, [ 'Tom', 'Cat' ]
function ExpOne_exp() {}
ExpOne_exp.prototype = new ExpOne();
ExpOne_exp.prototype.eat = function() {
console.log('eat');
};
//创建实例 ExpOne_expOne
let ExpOne_expOne = new ExpOne_exp(30); //传参无用
ExpOne_expOne.say(); //20, [ 'Tom', 'Cat' ]
ExpOne_expOne.eat(); //eat
ExpOne_expOne.age = 100;
//通过实例ExpOne_expOne对原型中引用类型值的进行修改
ExpOne_expOne.nameArr.push('Jolin');
ExpOne_expOne.say(); //100, [ 'Tom', 'Cat','jolin' ]
//创建实例ExpOne_expTwo
let ExpOne_expTwo = new ExpOne_exp();
ExpOne_expTwo.say(); // 20, [ 'Tom', 'Cat','jolin' ] //可见实例ExpOne_expTwo的引用类型的值受到了影响
expOne.nameArr.push('Jolin2');
expOne.say(); //18, [ 'Tom', 'Cat','Jolin2' ]
ExpOne_expTwo.say(); // 20, [ 'Tom', 'Cat','jolin' ]
ExpOne_exp.prototype.say = function() {
console.log('我要覆盖ExpOne的属性say');
};
ExpOne_expTwo.say(); //我要覆盖ExpOne的属性say
ExpOne_expOne.say(); //我要覆盖ExpOne的属性say
console.log(ExpOne_exp.prototype.constructor === ExpOne); //true 需要做如下纠正 ExpOne_exp.prototype.constructor = ExpOne_exp
2.借用构造函数来实现的继承(经典继承)
基于原型链的继承存在的不能传参以及原型的引用类型数据在多个实例共享使用时会出现被篡改的问题,出现了借用构造函数来实现的继承方案。
//创建动物的构造函数
function Anmail(age) {
this.age = age || 2;
this.nameArr = [ 'tom', 'cat' ];
}
//添加方法
Anmail.prototype.run = function() {
console.log('i am running');
};
let AnmailOne = new Anmail();
AnmailOne.run();
//创建子类 Cat 借用构造函数来实现的继承
function Cat(age) {
Anmail.call(this, age);
}
let catOne = new Cat(3);
catOne.nameArr.push('linlin');
console.log(catOne); //{ age: 3, nameArr: [ 'tom', 'cat','linlin' ] }
let catTwo = new Cat(4);
console.log(catTwo); //{ age: 4, nameArr: [ 'tom', 'cat' ] }
//catOne.run(); // 报错 TypeError: catOne.run is not a function
Cat.prototype.run = function() {
console.log('我需要在Cat的原型上再定义一次才可以在实例上访问到');
};
catTwo.run(); //需要在Cat的原型上再定义一次才可以在实例上访问到
3.js继承的组合继承
//创建父类构造函数
function Person(age, name) {
this.age = age;
this.name = name;
this.arr = [ 1, 2 ];
}
Person.prototype.say = function() {
console.log(this.age, this.name, this.arr);
};
let p1 = new Person(18, 'tom');
console.log(p1); //{ age: 18, name: 'tom', arr: [ 1, 2 ] }
//创建子类构造函数 使用组合继承方式继承Person的属性和方法
function Man(age, name, sex) {
Person.call(this, age, name);
this.sex = sex;
}
//通过prototype继承父类的方法
Man.prototype = new Person();
//为Man重新定义constructor
console.log(Man.prototype.constructor === Person);
Man.prototype.constructor = Man;
let man1 = new Man(10, 'Tom', 'male');
console.log(man1);
man1.say();
4.原型式继承
function create(o) {
function F() {}
F.prototype = o;
//console.log(new F());
return new F();
}
let obj = {
arr: [ 1, 2 ],
say: function() {
console.log(this.arr);
}
};
let F1 = create(obj);
console.log(F1); //{}
console.log(F1.arr); //[1,2]
F1.arr.push(3);
console.log(F1.arr); //[1,2,3]
let F2 = create(obj);
console.log(F2.arr); //[1,2,3]
5.寄生继承
function Person(obj) {
let newObj = Object.create(obj);
newObj.sayHi = function() {
console.log('Hi');
};
return newObj;
}
let objP1 = {
name: 'tom',
age: 20,
hobby: [ 'singing', 'swimming' ],
say: function() {
console.log('hello');
}
};
let newObjP1 = Person(objP1);
newObjP1.hobby.push('running');
console.log(newObjP1);
console.log(newObjP1.hobby); //[ 'singing', 'swimming', 'running' ]
console.log(newObjP1.name, newObjP1.age);
newObjP1.sayHi();
let newObjP2 = Person(objP1); //[ 'singing', 'swimming', 'running' ]
console.log(newObjP2.hobby);
6.寄生组合继承
function Create(obj) {
function P() {}
P.prototype = obj;
return new P();
}
function Person(name) {
this.name = name;
this.hobby = [ 'reading', 'fishing' ];
}
Person.prototype.say = function() {
console.log('hi');
};
function P(name, age) {
Person.call(this, name);
this.age = age;
}
P.prototype = Create(Person.prototype);
P.prototype.constructor = P; //修复构造函数指向
let p1 = new P('tom', 19);
p1.hobby.push('traveling');
console.log(p1); //{ name: 'tom', hobby: [ 'reading', 'fishing','traveling' ], age: 19 }
p1.say(); //hi
let p2 = new P('cat', 10);
console.log(p2); //{ name: 'tom', hobby: [ 'reading', 'fishing' ], age: 10 }
function Create(obj) {
function F() {}
F.prototype = obj;
return new F();
}
function inheritPrototype(child, parent) {
let prototype_inherit = Create(parent.prototype);
prototype_inherit.constructor = child;
child.prototype = prototype_inherit;
}
//封装inheritPrototype的目的:1.子类继承父类 2.重新修正子类constructor的指向
function Parent(name) {
this.name = name;
this.hobby = [ 'reading', 'fishing' ];
}
Parent.prototype.say = function() {
console.log('hello');
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
inheritPrototype(Child, Parent);
let p1 = new Child('tom', 10);
console.log(p1); //{ name: 'tom', hobby: [ 'reading', 'fishing' ], age: 10 }
console.log(Child.prototype.constructor); //Child
function Parent(name) {
this.name = name;
this.hobby = [ 'reading', 'fishing' ];
}
Parent.prototype.say = function() {
console.log('hello');
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
let p1 = new Child('tom', 10);
p1.hobby.push('he');
console.log(p1); //{ name: 'tom', hobby: [ 'reading', 'fishing' ], age: 10 }
let p2 = new Child('cat', 20);
console.log(p2); //{ name: 'cat', hobby: [ 'reading', 'fishing' ], age: 20 }
console.log(Child.prototype.constructor); //Child
7.最优的继承方案 es6的extends
class Person {
constructor(name) {
this.name = name;
this.hobby = [ 1, 2 ];
}
sayHi() {
console.log('hello');
}
play() {
console.log('basketball');
}
}
class Man extends Person {
constructor(name, age) {
super(name);
this.age = age;
}
sayHi() {
console.log('I am from Man');
}
}
let man1 = new Man('tom', 20);
console.log(man1);
man1.sayHi(); //I am from Man
man1.play(); //basketball