js继承的观点
js
里经常运用的以下两种继承体式格局:
原型链继承(对象间的继承)
类式继承(组织函数间的继承)
因为js
不像java
那样是真正面向对象的言语,js
是基于对象的,它没有类的观点。所以,要想完成继承,能够用js
的原型prototype机制或许用apply
和call
要领去完成
在面向对象的言语中,我们运用类
来建立一个自定义对象。但是js
中一切事物都是对象,那末用什么方法来建立自定义对象呢?这就须要用到js
的原型:
我们能够简朴的把prototype
看作是一个模版,新建立的自定义对象都是这个模版(prototype
)的一个拷贝 (实际上不是拷贝而是链接,只不过这类链接是不可见,新实例化的对象内部有一个看不见的__Proto__
指针,指向原型对象)。
js
能够经由历程组织函数和原型的体式格局模仿完成类的功用。 别的,js
类式继承的完成也是依托原型链来完成的。
原型式继承与类式继承
类式继承
是在子范例组织函数的内部挪用超范例的组织函数。
严厉的类式继承并非很罕见,平常都是组合著用:
function Super(){
this.colors=["red","blue"];
}
function Sub(){
Super.call(this);
}
原型式继承
是借助已有的对象建立新的对象,将子类的原型指向父类,就相当于加入了父类这条原型链
原型链继承
为了让子类继承父类的属性(也包含要领),起首须要定义一个组织函数。然后,将父类的新实例赋值给组织函数的原型。代码以下:
<script>
function Parent(){
this.name = 'mike';
}
function Child(){
this.age = 12;
}
Child.prototype = new Parent();//Child继承Parent,经由历程原型,构成链条
var test = new Child();
alert(test.age);
alert(test.name);//获得被继承的属性
//继承原型链继承
function Brother(){ //brother组织
this.weight = 60;
}
Brother.prototype = new Child();//继承原型链继承
var brother = new Brother();
alert(brother.name);//继承了Parent和Child,弹出mike
alert(brother.age);//弹出12
</script>
以上原型链继承还缺乏一环,那就是Object
,一切的组织函数都继承自Object
。而继承Object
是自动完成的,并不须要我们本身手动继承,那末他们的从属关联是如何的呢?
肯定原型和实例的关联
能够经由历程两种体式格局来肯定原型和实例之间的关联。操作符instanceof
和isPrototypeof()
要领:
alert(brother instanceof Object)//true
alert(test instanceof Brother);//false,test 是brother的超类
alert(brother instanceof Child);//true
alert(brother instanceof Parent);//true
只如果原型链中涌现过的原型,都能够说是该原型链派生的实例的原型,因而,isPrototypeof()
要领也会返回true
在js
中,被继承的函数称为超范例(父类,基类也行),继承的函数称为子范例(子类,派生类)。运用原型继承主要由两个题目:
一是字面量重写原型会中缀关联,运用援用范例的原型,而且子范例还没法给超范例通报参数。
伪类处理援用同享和超范例没法传参的题目,我们能够采纳“借用组织函数”手艺
借用组织函数(类式继承)
<script>
function Parent(age){
this.name = ['mike','jack','smith'];
this.age = age;
}
function Child(age){
Parent.call(this,age);
}
var test = new Child(21);
alert(test.age);//21
alert(test.name);//mike,jack,smith
test.name.push('bill');
alert(test.name);//mike,jack,smith,bill
</script>
借用组织函数虽然处理了适才两种题目,但没有原型,则复用无从谈起,所以我们须要原型链+借用组织函数
的形式,这类形式称为组合继承
组合继承
<script>
function Parent(age){
this.name = ['mike','jack','smith'];
this.age = age;
}
Parent.prototype.run = function () {
return this.name + ' are both' + this.age;
};
function Child(age){
Parent.call(this,age);//对象假装,给超范例传参
}
Child.prototype = new Parent();//原型链继承
var test = new Child(21);//写new Parent(21)也行
alert(test.run());//mike,jack,smith are both21
</script>
组合式继承是比较经常运用的一种继承要领,其背地的思绪是 运用原型链完成对原型属性和要领的继承,而经由历程借用组织函数来完成对实例属性的继承。如许,既经由历程在原型上定义要领完成了函数复用,又保证每一个实例都有它本身的属性。
call()
的用法:挪用一个对象的一个要领,以另一个对象替代当前对象。
call([thisObj[,arg1[, arg2[, [,.argN]]]]])
原型式继承
这类继承借助原型并基于已有的对象建立新对象,同时还不必建立自定义范例的体式格局称为原型式继承
<script>
function obj(o){
function F(){}
F.prototype = o;
return new F();
}
var box = {
name : 'trigkit4',
arr : ['brother','sister','baba']
};
var b1 = obj(box);
alert(b1.name);//trigkit4
b1.name = 'mike';
alert(b1.name);//mike
alert(b1.arr);//brother,sister,baba
b1.arr.push('parents');
alert(b1.arr);//brother,sister,baba,parents
var b2 = obj(box);
alert(b2.name);//trigkit4
alert(b2.arr);//brother,sister,baba,parents
</script>
原型式继承起首在obj()
函数内部建立一个暂时性的组织函数 ,然后将传入的对象作为这个组织函数的原型,末了返回这个暂时范例的一个新实例。
寄生式继承
这类继承体式格局是把原型式+工场形式结合起来,目标是为了封装建立的历程。
<script>
function create(o){
var f= obj(o);
f.run = function () {
return this.arr;//一样,会同享援用
};
return f;
}
</script>
组合式继承的小题目
组合式继承是js
最经常运用的继承形式,但组合继承的超范例在运用历程中会被挪用两次;一次是建立子范例的时刻,另一次是在子范例组织函数的内部
<script>
function Parent(name){
this.name = name;
this.arr = ['哥哥','mm','父母'];
}
Parent.prototype.run = function () {
return this.name;
};
function Child(name,age){
Parent.call(this,age);//第二次挪用
this.age = age;
}
Child.prototype = new Parent();//第一次挪用
</script>
以上代码是之前的组合继承,那末寄生组合继承,处理了两次挪用的题目。
寄生组合式继承
<script>
function obj(o){
function F(){}
F.prototype = o;
return new F();
}
function create(parent,test){
var f = obj(parent.prototype);//建立对象
f.constructor = test;//加强对象
}
function Parent(name){
this.name = name;
this.arr = ['brother','sister','parents'];
}
Parent.prototype.run = function () {
return this.name;
};
function Child(name,age){
Parent.call(this,name);
this.age =age;
}
inheritPrototype(Parent,Child);//经由历程这里完成继承
var test = new Child('trigkit4',21);
test.arr.push('nephew');
alert(test.arr);//
alert(test.run());//只同享了要领
var test2 = new Child('jack',22);
alert(test2.arr);//援用题目处理
</script>
call和apply
全局函数apply
和call
能够用来转变函数中this
的指向,以下:
// 定义一个全局函数
function foo() {
console.log(this.fruit);
}
// 定义一个全局变量
var fruit = "apple";
// 自定义一个对象
var pack = {
fruit: "orange"
};
// 等价于window.foo();
foo.apply(window); // "apple",此时this即是window
// 此时foo中的this === pack
foo.apply(pack); // "orange"