在面向对象的程序设计语言中,类和类之间有显式的继承关系,一个类可以显式的指定继承了哪个类,子类将具有父类的所有属性和方法。js虽然也支持类、对象的概念,但没有继承的概念,只能通过特殊的手段来扩展原有的js类。js中有三种继承方式。
1. prototype属性实现继承
js的所有类都有一个prototype属性,如果为js类的prototype属性增加属性、方法,则可视为对原有类的扩展。可以理解为:增加prototype属性的类继承了原有类----- 伪继承机制. 具体用法如下:function person(name,age){
this.name=name;
this.age=age;
}
person.prototype.sayhello=function(){
console.log(this.name+"打招呼");
}
var p=new person("aaa",20);
p.sayhello();
function student(grade){
this.grade=grade;
}
student.prototype=new person("未命名",0);
student.prototype.intro=function(){
console.log("%s is a student,grade is %d,age is %d",this.name,this.grade,this.age);
}
var s=new student(5);
s.name="ss";
console.log(s instanceof student);
console.log(s instanceof person);
s.sayhello();
s.intro();
结果为
上面定义了一个person类,然后使用prototype属性为person类定义了sayhello()方法。
然后定义一个student类,并将student类的prototype属性设为person对象。这就表明student的原型是person对象,也就是相当于设置student继承了person,这样student类就会得到person类的属性和方法。
然后通过结果的两个true,表明student的实例s不仅是student类的实例,还是person类的实例。此外,student对象既可以调用student类定义的实例方法,还可以调用person定义的实例方法。
这种方法继承的是方法(在函数外定义的含prototype属性的方法),这种“伪继承”的实质是修改了原有类,而不是产生一个新的类。一般不在函数内定义方法,因为函数内定义方法,不仅性能低下(每次创建实例时,都会创建一个新的方法,而我们只需要一个就够了),而且方法中的局部变量会产生闭包。
还有一类伪继承,这种继承的关键在于子类构造器需要以this作为调用者来调用父类构造器。这样父类构造器中的this就会变成代表子类,子类就可以得到原父类定义的实例属性和方法。有下面两种形式。
2. 构造器实现伪继承
这种方式不常用,通常使用call()或apply()实现伪继承。用法如下:以子类的this为调用者,直接调用父类的构造器,这样父类的this就全部换成了当前的子类。
3. 使用apply和call实现伪继承
这也是通过this来调用父类构造器的方法实现伪继承的,只不过是通过call或apply方法,这种方法中非常直观的显示出调用者是谁。看下面代码:<script>
function person(name,age){
this.name=name;
this.age=age;
this.sayhello=function(){
console.log(this.name+"打招呼");
}
}
var p=new person("aa",22);
p.sayhello();
function student(name,age,grade){
person.call(this,name,age);
this.grade=grade;
}
student.prototype.intro=function(){
console.log("%s is a student,grade is %d,age is %d",this.name,this.grade,this.age);
}
var s=new student("ss",34,5);
console.log(s instanceof student);
console.log(s instanceof person);
s.sayhello();
s.intro();
</script>