继承
- 继承就是通过某种方式让一个对象可以访问到另一个对象中的属性和方法,我们把这种方式称之为继承。
- 生活中的继承是传承,而代码中的继承是总量的增加,在其基础上添加继承来的缺失的属性。
原型链继承-prototype属性:
//首先构造两个函数
function Aa(){
this.car="大众"
this.house="诚城"
}
function Bb(name,age){
this.name=name;
this.age=age;
}
// 此时如果想让Bb构造出来的对象,获取Aa的对象,就可以通过原型链继承的方式去获取
第一种写法的继承
function Aa(){
this.car="大众"
this.house="诚城"
}
function Bb(name,age){
this.name=name;
this.age=age;
}
// 把Aa放在Bb的原型对象上, 就可以把Aa的属性直接给到Bb,Bb就可以用Aa中的方法
Bb.prototype=new Aa()
var Cc=new Bb("李二",18);
console.log(Cc)// 此时打印的Cc不仅有其构造函数Aa的值还有Bb的值
// 因为Aa也是一个构造函数,所以此时Cc分不清他的构造器是哪一个,跑偏了跑到了Aa上面,打印一下 constructor 就可以看到
console.log(Cc.constructor)
//constructor 指向对象的构造函数
// 跑偏了就得通过手动给他值回来,让Bb原型对象上的构造函数也指向Bb
Bb.prototype.constructor=Bb
cosole.log(Cc.constructor)//此时Cc重新指向Bb
第二种方法,由于Aa对象中不变的属性都可以直接写入Aa.prototype 中,所以可以让Bb跳过Aa的实例化过程直接继承Aa.prototype
function Aa(){}
Aa.prototype.car="大众"
Aa.prototype.house="诚城"
function Bb(name,age){
this.name=name;
this.age=age;
}
Bb.prototype=Aa.prototype;//直接把Bb的原型对象指向Aa的原型对象,或者说Bb的原型对象继承Aa的原型对象
Bb.prototype.constructor=Bb// 此时的继承链紊乱了,所以还需要重新指向它本身
var Cc=new Bb("张三",18)
console.log(Cc);
console.log(Cc.constructor);
Bb.prototype.car="长安";
var Dd=new Aa()
console.log(Dd.car)
// 此时,虽然修改的是Bb的原型对象,但把Aa的也修改了,所以此时,Aa的构造函数Dd.car的值也是长安
-----------------------------------------------------
//2022.11.12新理解
//此时虽然修改的是Bb的原型对象,但Bb上面并无car这个值,是因为Aa挂载到了Bb原型链上,通过寻找找到了Aa,然后进行了修改,所以这里直接修改的Aa原型链上面的car值。
空对象继承
- 以下,就通过创建一个新对象解决了继承完别人的东西还要更改别人东西的问题
function AA(){}
AA.prototype.car="奔驰";
AA.prototype.house="碧桂园"
function BB(name,age){
this.name=name;
this.age=age;
}
function CC(){}// 生成一个空的构造函数
CC.prototype=AA.prototype;// 让空函数的原型对象指向AA的原型对象
BB.prototype=new CC();// 让BB的原型对象等于CC的调用,此时一定要调用,不调用是无效的
BB.prototype.constructor=BB//让BB的原型对象构造函数重新指向BB
var d1=new BB("张三",18);
console.log(d1);
console.log(d1.car)
BB.prototype.car="奥迪";
var d2=new BB("张三",19)
console.log(d2.car);
console.log(d2)
var d3=new AA();
console.log(d3);
console.log(d3.car)
//这里是因为,CC是继承的AA的原型对象,BB继承CC的原型对象,在BB修改继承来的值时,会顺着原型链去找,找到CC那里进行修改,也就不需要再去修改AA的值
空对象继承的封装
把继承的过程封装成函数
function AA(){}
AA.prototype.car="奔驰";
AA.prototype.hpuse="别墅";
function BB(name,age){
this.name=name;
this.age=age;
}
// 通过函数传参的形式把两个函数传进去
function extend(partent,child){
function CC(){}
CC.prototype=parent.prototype;
child.prototype=new CC;
child.prototype.constructor=child;
}
// 但注意,此时传的参数要和上面的两个函数名一样 // 对应的parent和child参数决定了谁继承谁
extend(AA,BB);
var d1= new BB("李二",18);
console.log(d1);
console.log(d1.car);
构造函数的绑定继承
#function函数中
1.作为Dom对象的事件处理函数,使用this时,this指向当前Dom对象
2.作为对象的方法使用时,this指向当前对象
3.作为构造函数使用时,this指向当前构造函数所实例化出来的对象
4.在函数嵌套时,内层函数不会继承外层函数this的指向。
-- 如果想让内层函数,使用外层函数this指向时,可以在外层函数中用一个变量(that)保存this。
--由于作用域链的原因,that对于内层函数是可见的
5.作为全局函数使用this时,this指向window;
call
语法:
A.call (B, att1,att2)
表示B继承的是A的这两个属性,把A的两个属性的指向指向了B,在B函数中B被this代替,具体写法如下
function AA(car,house){
this.car=car;
this.house=house;
}
function BB(name,age){
this.name=name;
this.age=age;
AA.call(this,"奔驰","汤臣一品")//表示BB继承的是AA的属性并指向BB,并传参AA,在BB函数中BB被this代替了
}
var d1=new BB("李二",18);
console.log(d1);
console.log(d1.car);
console.log(d1.house);
apply
语法:
A.apply(B,[att1,att2]); 与call的用法完全一致,只是语法写法不同
表示B继承的是A的这两个属性,把A的两个属性的指向指向了B,在B函数中B被this代替,具体写法如下
function AA(car,house){
this.car=car;
this.house=house;
}
function BB(name,age){
this.name=name;
this.age=age;
AA.apply(this,["奔驰","汤臣一品"])//表示BB继承的是AA的属性并指向BB,并传参AA,在BB函数中BB被this代替了
}
var d1=new BB("李二",18);
console.log(d1);
console.log(d1.car);
console.log(d1.house);