前言
说起继承,情不自禁的会想起封装和多态,那我在这里简单阐述一下多态和封装,后面我们重点说JS怎么实现的继承。
封装:可以称为包装,一堆重复的代码放在一个函数中,用的时候直接调取。一系列类似的方法放在一个对象中。
多态:一个对象有不同的行为,或者同一个行为针对不同的对象,产生不同的结果。
继承
首先我先说明一点,JavaScript不是一门面向对象的语言,JavaScript是一门基于对相关的语言,JavaScript可以通过构造函数来模拟class来实现。举个栗子:
<script>
//动物有名字,有体重,有吃东西的行为
//小狗有名字,有体重,有毛色,有吃东西的行为,还有要人的行为
//哈士奇名字,有体重,有毛色,性别,有吃东西的行为,咬人的行为,逗主人开心的行为
//动物的构造函数
function Animal(name,weight) {
this.name = name;
this.weight = weight;
}
//动物的原型的方法
Animal.prototype.eat = function () {
console.log("天天吃东西,就是吃");
}
//狗的构造函数
function Dog(color) {
this.color = color;
}
Dog.prototype = new Animal("哮天犬", "50kg");
Dog.prototype.bitePerson = function () {
console.log("汪汪 ~~咬死你");
};
//哈士奇
function ErHa(sex) {
this.sex = sex;
}
ErHa.prototype = new Dog("黑白色");
ErHa.prototype.playHost = function () {
console.log("拆家 ... 开心不 .. 惊喜不 ..");
};
var erHa = new ErHa("雄性");
console.log(erHa.name, erHa.weight, erHa.color);
erHa.eat();
erHa.bitePerson();
erHa.playHost();
</script>
最后的输出结果为:
解释一下这个例子:有个动物的构造函数,动物有自己的原型对象。有个狗的构造函数,狗的实例对象改变了指向,指向了动物的原型对象。有个二哈的构造函数,二哈的实例对象指向了狗的实例对象,所以二哈有了所有的方法。是不是和原型很像,没错继承的本质就是原型。
借用构造函数来继承
<script>
function person(name,age,sex,weight) {
this.name = name;
this.age = age;
this.sex = sex;
this.weight = weight;
}
person.prototype.sayhi = function () {
console.log("您好");
}
function student(name,age,sex,weight,score) {
//借用构造函数
person.call(this, name, age, sex, weight);
this.score = score;
}
var stu1 = new student("小明", 10, "10kg", "110");
console.log(stu1.name, stu1.age, stu1.sex, stu1.weight, stu1.score);
var stu2 = new student("小换", 11, "11kg", "120");
console.log(stu2.name, stu2.age, stu2.sex, stu2.weight, stu2.score);
var stu3 = new student("小画", 12, "12kg", "130");
console.log(stu3.name, stu3.age, stu3.sex, stu3.weight, stu3.score);
</script>
借用构造函数实现继承,主要的代码就是:
function student(name,age,sex,weight,score) {
//借用构造函数
person.call(this, name, age, sex, weight);
this.score = score;
}
本来student中是没有name,age,sex,weight这些属性的。那就需要Call这个方法来‘借’,借过来就是自己了,就可以使用了。但是它有个致命的缺陷就是方法借不过来!那么就有了组合继承。
组合继承
组合继承=原型继承+借用构造函数继承
<script>
//组合继承:原型继承+借用构造函数继承
function person(name,age,sex) {
this.name = name;
this. age = age;
this.sex = sex;
}
person.prototype.sayHi = function () {
console.log("qwer");
};
function student(name,age,sex,score) {
//借用构造函数
person.call(this, name, age, sex);
this.score = score;
}
//改变原型指向
student.prototype = new person();
student.prototype.eat = function () {
console.log("吃东西");
};
var stu = new student("小阿斯顿", 20, "男", "100");
console.log(stu.name, stu.age, stu.sex, stu.score);
stu.sayHi();
stu.eat();
</script>
运行结果为:
我们通过借构成函数来实现属性的继承,通过改变原型的指向来继承方法。
拷贝继承
拷贝继承:那一个对象中的属性或者方法复制到另一个对象中
function person() {
}
person.prototype.age = 10;
person.prototype.sex="男";
person.prototype.height = 100;
person.prototype.play = function () {
console.log("玩得好开心");
}
var obj2 = {};
//person 的构造中有原型prototype,prototype就是一个对象,那么里面age,sex,height,play都是改对象中的属性或者方法
for (var key in person.prototype) {
obj2[key] = person.prototype[key];
}
console.log(obj2.age, obj2.sex, obj2.height, obj2.play());
改变原型指向是栈里的两个对象指向堆里一个地址。拷贝继承是在堆里开辟一个新的空间,两个对象分别指向自己的地址。
总结
对,没错。继承的本质就是原型。