什么是继承?
一个原本没有某些方法和功能的对象,用过一些方法拿到另一个对象的属性和方法
构造函数的继承:
function Fn(name){
this.name = name;
this.show = function(){
alert(this.name);
}
}
var obj1 = new Fn("AAA");
var obj2 = new Fn("BBB");
obj1.show()
obj2.show()
改变this的指向 只能继承构造函数不能继承原型 可以向父类传参
call/apply继承:
function Father(skill){
this.skill = skill;
this.show = function(){
alert("我会"+this.skill);
}
}
function Son(abc){
//这里的this指向函数Son的实例化对象
//将Father里面的this改变成指向Son的实例化对象,
//当相遇将father里面所有的属性和方法都复制到了son身上
//Father.call(this,abc);//继承结束,call适合固定参数的继承
//Father.apply(this,arguments);//继承结束,apply适合不定参数的继承
}
var f = new Father("绝世木匠”);
var s = new Son("一般木匠");
f.show()
s.show();
//优点:创建子类实例时,可以向父类的构造器传参;
//缺点:只能继承构造器中定义的属性和方法,不能继承原型上定义的属性和方法
call()方法接受的是若干个参数的列表,
apply()方法接受的是一个包含多个参数的数组。
这里要注意的是
两个参数都不是必填的,第一个参数在函数中使用时,根据场景不同指向也不一样,当不填时 默认指向的是window对象。
call/apply继承的区别
继承方面两者用法几乎一致,唯一的区别就是传参的时候,call是参数队列,apply是数组
function father(name, age) {
this.name = name;
this.age= age;
}
function child1(name, age) {
father.call(this, name, age);
this.category = 'child1';
}
function child2(name, age) {
father.apply(this, [name, age]);
this.category = 'child2';
}
var first= new child1('one', 11);
var second= new child2('two', 22);
console.log(first.category ,first.name,first.age) // child1,one,11
console.log(second.category ,second.name,second.age) //child2,two,22
原型对象继承:继承原型
缺点:只能继承原型,不能传参
优点:简单 方便 可以继承原型上的属性和方法
使原型prototype进行深拷贝
function Parent(n){
this.name = n;
}
Parent.prototype.skill = function(){
console.log(this.name + "是鉴定师");
}
function Child(n){}
// 注意:对象的深浅拷贝
// Child.prototype = Parent.prototype;
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
// Child.prototype.skill = function(){
// console.log("采矿");
// }
var p = new Parent("大老王");
console.log(p)
p.skill();
var c = new Child("小老王");
console.log(c)
c.skill();
原型链继承:
通过给子设置实例的方式 给子添加一层原型链的方式
function SuperType(){
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.Fun = function(){
};
function SubType(){
}
//继承了SuperType
SubType.prototype = new SuperType();
//优点:既能继承原型又能继承构造函数
//缺点:复杂 不方便传参
混合继承:
构造函数继承 + 原型继承
特点:
使用call或apply继承父类的构造器中的内容,使用原型继承,继承父类的原型
function Father(skill,id){
this.skill = skill;
this.id = id;
}
Father.prototype.show = function(){
alert("我是father,这是我的技能"+this.skill);
}
function Son(){
Father.apply(this,arguments);
}
//如果不做Son的原型继承Father的原型,此时会报错:son.show is not a function
for(var i in Father.prototype){
Son.prototype[i] = Father.prototype[i];
}
//因为,如果不让Son的原型等于Father的原型,Son使用apply是继承不到原型上的方法
Son.prototype.show = function(){
alert("我是son,这是我的技能"+this.skill);
}
var f = new Father("专家级铁匠","father");
var s = new Son("熟练级铁匠","son");
f.show();
s.show();
//优点:方便传参 多继承
//缺点:复杂
ES6 class继承:
class child extends Parent{
constructor(n){
super(n);
}
}
//构造函数 + 原型链
//extends 关键字继承父级属性的方法
//优点:简单方便易操作 语法层面继承 属性和方法都能继承 参数很好处理
//缺点:兼容性 IE5
//super关键字既可以当做函数使用,也可以当做对象使用
//super作为函数调用时 代表父类构造函数 ES6要求,子类的构造函数必须执行一个super
//super作为对象使用时 在普通方法中指向父类的原型对象,在静态方法中指向对象
检测两个对象之间是否存在继承关系
Fn.prototype.isPrototypeOf(f)查看Fn的prototype对象是否是f的原型
f instanceof FN 查看 f 对象是否是构造函数 Fn 的实例