继承的介绍
JS 是一种面向对象的 弱类型的 解释性的语言
弱类型 声明变量的时候不需要注明数据类型
int a =1;
float//(强类型)
var a=1.2;
解释性 解释一句执行一句 编译性 一次性全部翻译完 然后再执行
面向对象 封装 继承 多态 (js语言没有多态)
封装 将一个功能都放在一个对象里面 只需要向外界暴露一个接口 需要使用的时候 直接调接口就可以了并不需要管底层是怎么实现的
push //向数组的最后添加一个元素
var arr=[12,23];
arr.push(15);
继承:是指js对象之间的继承 如果我们想让一个对象拥有另一个对象的属性或者方法 那么就可以让这个对象继承另一个对象
实现继承的方式
1.实现构造函数来实现继承
实现方式:使用call等方法 是一个对象的this指向另一个对象 从而让其拥有这个对象的属性和方法
缺点:无法继承父类原型上面的方法 对于子类不需要的方法 每次创建都会拥有 浪费内存空间
有很多构造函数的情况下,如果需要给所有的构造函数添加属性 ,那么就需要分别去加 就不便于维护
function Perent(name,age){
this.name=name;
this.age=age;
this.work=function(){
console.log("我要赚钱");
}
}
Perent.prototype.test=function(){
console.log(111);
}
Perent.prototype.type="人类";
var p1=new Perent("父亲",36);
// function Child(name,age,gender){
// this.name=name;
// this.age=age;
// }
// var c1=new Child("孩子",12);
// call apply bind 修改this指向
function Child(name,age){
Perent.call(this,name,age)
}
var c2=new Child("amy",12);
console.log(c2);
//c2.test(); //报错
c2.work() //执行了函数体
就是说只是把父亲构造函数里面的属性和方法继承了 但是父类原型里面的方法继承不了
创建的child对象并不需要work方法 但每次创建都会有 浪费空间
2.原型拷贝继承(混入式继承)
实现方式:使用for-in遍历父类原型里面的所有属性 依次加入子类的原型中
缺点:原型中子类不需要的方法或者属性也继承过来了 占用内存空间
function Perent(name,age){
this.name=name;
this.age=age;
this.work=function(){
console.log("我要赚钱");
}
}
Perent.prototype.test=function(){
console.log(111);
}
Perent.prototype.type="人类";
function Child(name,age){
this.name=name;
this.age=age;
}
//原型对象拷贝
for(var key in Perent.prototype){
Child.prototype[key]=Perent.prototype[key];
console.log(Perent.prototype[key]);
}
var c1=new Child("张三",12);
c1.test();
console.log(c1.type);
3.原型链继承
实现方法:利用原型链来实现继承 父类的一个实例化对象作为子类的原型
缺点:子类实例和父类实例的原型对象上有成员的共享问题
function Perent(name,age){
this.name=name;
this.age=age;
this.work=function(){
console.log("我要赚钱");
}
}
Perent.prototype.test=function(){
console.log(111);
}
Perent.prototype.type="人类";
function Child(name,age){
this.name=name;
this.age=age;
}
Child.prototype=new Perent();
console.log(Child.prototype.constructor);
//重新替换原型之后 构造函数并不指向原构造函数 所以要将构造函数指向原函数
Child.prototype.constructor=Child;
Child.prototype=new Perent();
var c1=new Child("张三",12);
console.log(c1.type);
c1.test();
为什么不直接使用Child.prototype=Perent?
把父类的构造函数直接替换掉子类的原型会导致 父类构造函数的私有属性发生变化
甚至有些成员 父类构造函数并不需要
Child.prototype=Perent;
Child.prototype.study=function(){
console.log("good good study");
}
console.dir(Perent);
Perent.study();
4.组合继承(原型链 和call继承组合)
function Father(){
this.name=name;
this.run=function(){
console.log(this.name+"我要跑步");
}
}
Father.prototype={
constructor:Father,
type:"人类",
eat:function(){
console.log(this.name+"我要吃饭");
}
}
function Son(age){
//这个是继承父类构造函数里面的属性或者方法
Father.call(this);
this.age=age;
this.study=function(){
console.log(this.name+"我要开始学习了");
}
}
//继承父类原型中的成员
Son.prototype=new Father();
Son.prototype.constructor=Son;
Son.prototype.sleep=function(){
console.log(this.name+"我要睡觉了");
}
var s1=new Son(12);
//这个是父类构造函数里面的方法
s1.run();
//是父类原型里面的方法
s1.eat();
console.log(s1.type);
//自己构造函数里面的方法
s1.study();
//自己的原型里面的方法
s1.sleep();