关于JavaScript的继承
2018-03-08 本文已影响0人
HancockTong
继承是OO 语言中的一个最为人津津乐道的概念。许多OO 语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。如前所述,由于函数没有签名,在ECMAScript 中无法实现接口继承。ECMAScript 只支持实现继承,而且其实现继承主要是依靠原型链来实现的。 ——引用自《JavaScript高级程序设计》
原型链实现继承
基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法
。也就是使子类原型对象指向父类的实例
以实现继承,即重写类的原型,弊端是不能直接实现多继承。
function Parent() {
this.sayAge = function() {
console.log(this.age);
}
}
function Child(firstname) {
this.fname = firstname;
this.age = 21;
this.saySomeThing = function() {
console.log(this.fname);
this.sayAge();
}
}
Child.prototype = new Parent();
var myChild = new Child('Jackie');
myChild.saySomeThing(); // Jackie 21
借用构造函数实现多继承
这里是使用伪造对象来实现多继承,这种技术的基本思想相当简单,即在子类型构造函数的内部调用超类型构造函数。
function Parent(name) {
this.name = name;
this.sayName = function() {
console.log(this.name);
}
}
var iParent = new Parent('James');
iParent.sayName();
function Child(name) {
this.parent = Parent;
this.parent(name);
delete this.parent;
this.saySomeThing = function() {
console.log('my name: ' + this.name);
this.sayName();
}
}
var iChild = new Child('Jackie');
iChild.saySomeThing();
console.log(iChild.constructor);
运行结果:
image.png
Call/Apply方法实现继承
改变函数内部的函数上下文this,使它指向传入函数的具体对象,该种方式不能继承原型链。
1
function Parent(firstname) {
this.fname = firstname;
this.age = 21;
this.sayAge = function() {
console.log(this.age);
}
}
function Child(firstname) {
Parent.call(this, firstname); // 将this传给父类函数,这个时候的Parent中的this已经被Child所代替
//Parent.apply(this, [firstname]); // 与call作用相同
this.saySomeThing = function() {
console.log(this.fname);
this.sayAge();
}
this.getName = function() {
return firstname;
}
}
var myChild = new Child('Jackie');
myChild.saySomeThing(); //Jackie 21
console.log(myChild.constructor);
myChild.constructor == Child; // true;
2
function Parent(add,net,no,teacher) {
this.add = add;
this.net = net;
this.no = no;
this.teacher = teacher
}
function Child(name,age,sex,id) {
this.name = name;
this.sex = sex;
this.age = age;
this.id = id;
Parent.call(this,"山东","www.baidu.com","1608","ccy"); //这个时候的Parent中的this已经被Child所代替
}
var child = new Child("fangMing","18","男","10086");
console.log(child.add)
混合模式
function Parent()
{
this.sayAge=function()
{
console.log(this.age);
}
}
Parent.prototype.sayParent=function()
{
alert("this is parentmethod!!!");
}
function Child(firstname)
{
Parent.call(this);
this.fname=firstname;
this.age=40;
this.saySomeThing=function()
{
console.log(this.fname);
this.sayAge();
}
}
Child.prototype=new Parent();
var child=new Child("张");
child.saySomeThing();
child.sayParent();
ES6继承
ES6 class的继承与java的继承大同小异,如果学过java的话应该很容易理解,都是通过extends关键字继承。
ES6子类继承父类,必须在constructor函数的第一行调用super();之后才能使用关键字this,这是因为子类中没有自己的this对象,而是继承父类的this对象,然后才能为这个this添加相应的属性和方法。不然就会报错,相当于Parent.apply(this);而ES6则正好和这个相反,它先创造了自己的this对象,然后才添加父类的方法属性到这个对象里。
super在子类中一般有三种作用:
- 作为父类的构造函数调用,就是上面所说的那种方法。
- 在普通方法中,作为父类的实例调用
- 在静态方法中,作为父类调用
class Animal {
//构造函数
constructor(props) {
this.name = props.name || '未知';
}
eat() {
alert(this.name + "在吃东西...");
}
}
//class继承
class Bird extends Animal {
//构造函数
constructor(props) {
//调用实现父类的构造函数
super(props);
this.type = props.type || "未知";
}
fly() {
alert(this.name + "在飞...");
}
}
var myBird = new Bird({
name: '鹦鹉'
})
myBird.eat();
myBird.fly();