继承
JavaScrip是门面向对象的语言,也有继承的概念。继承有两点有用的服务。1.它是代码重用的一种形式;2.引入类型系统规范。它是门基于原型的语言,意味它的对象可以直接从其他对象继承。(子类继承父类)
父类:
//es5(类是构造函数写法) es6(class)
function Animal(name, sex) {
this.name = name || "动物";
this.sex = sex || "性别";
this.sleep = function () {
return this.name + "睡觉";
}
}
1.原型链继承
//子类 猫
function Cat(){
}
//子类 老鼠
function Mouse(){
}
Cat.prototype=new Animal();
Cat.prototype.eat=function (){
return this.name+"吃饭";
}
Cat.prototype.name="小猫";
Cat.prototype.sex="公";
//实例化子类
var cat=new Cat();
console.log(cat.name);
Mouse.prototype=new Animal();
Mouse.prototype.name="乔治";
Mouse.prototype.sex="公";
var mouse=new Mouse();
var mouse1=new Mouse();
console.log(mouse.name);
console.log(mouse1.name);
// 直接继承
//子类的实例 即是自身 也是父类
console.log(cat instanceof Cat);
console.log(cat instanceof Animal);
console.log(cat);
缺点:prototype属性共享; 给予类原型追加方法或者属性必须在原型继承之后;原型继承不能进行多继承
2.构造继承
基本思想:在子类型构造函数的内部调用超类型构造函数(通过使用apply()和call()方法也可以在(将来)新创建的对象上执行构造函数);
//call apply 来继承的
//对象里面的this替换 参数的区别 1.替换的对象 2.参数列表 call(this,1,2,3,4,5) apply(this,[1,2,3,4,5,6])
//子类 猫
/*function AnimalType(type){
this.type=type || "类别";
}
function Cat(name,sex,type){
Animal.call(this,name,sex);
AnimalType.apply(this,[type]);
this.eat=function (){
return this.name+"爱吃老鼠";
}
}
//子类 老鼠
function Mouse(name,sex,type){
Animal.call(this,name,sex);
AnimalType.apply(this,[type]);
this.eat=function (){
return this.name+"爱偷大米";
}
}
//实例化对象
var cat=new Cat("小花","公","猫科");
var cat1=new Cat("小黑","母","猫科");
console.log(cat.eat());
console.log(cat1.eat());
console.log(cat instanceof Animal);
console.log(cat);
var mouse=new Mouse("小小","公","鼠科");
console.log(mouse);
优点:在创建子类的实例的时候可以向父类传参;它可以实现多继承;子类的实例只能是自身
组合继承 (原型+构造)
基本思想:使用原型链实现对原型属性和方法的继承(主要想继承方法),而通过借用构造函数来实现对实例属性的继承(子类型的实例内部存在同名属性,从而对父类型的同名属性进行屏蔽);最后同时避免了原型链会被继承时会共享同一个父类型属性和借用构造函数的函数复用的缺陷
function AnimalType(type) {
this.type = type || "类别";
}
//子类 猫
function Cat(type) {
AnimalType.call(this, type);
}
Cat.prototype = new Animal();
Cat.prototype.name = "小花";
//子类 老鼠
function Mouse() {
}
var cat = new Cat("猫科");
console.log(cat);
//可以实现多继承 有数据可以共享
// 子类的实例即是自身 也是父类
console.log(cat instanceof Animal);
console.log(cat);
function Grade(score) {
this.score = score || "0";
}
function Person(name, sex) {
this.name = name || "人";
this.sex = sex || "默认";
}
function Job(job) {
this.job = job || "闲人"
}
function Children(name, sex, job, score) {
Person.apply(this, [name, sex]);
Job.call(this, job);
Grade.call(this, score);
}
var s = new Children("小强", "男", "学生", 485);
var s1 = new Children("小花", "女", "学生", 657);
console.log(s);
console.log(s1);
缺点:两次调用父类构造函数:(第一次是在创建子类原型的时候,第二次是在子类构造函数内部) ;从而造成子类继承父类的属性,一组在子类实例上,一组在子类原型上(即在子类原型上创建不必要的多余的属性)
实例继承
//子类 猫
function Cat(name, sex) {
this.eat=function (){
}
var animale = new Animal(name, sex);
return animale;
}
//子类 老鼠
function Mouse() {
}
//不限制调用方式
//子类的实例不是本身 而是父类
var cat=new Cat("小猫","公");
console.log(cat);
var cat1=Cat("小花","母");
console.log(cat1);
console.log(cat instanceof Cat);
console.log(cat instanceof Animal);
组合寄生:
概念:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。
基本思想:没有必要为了指定子类型的原型而调用超类型的构造函数(函数复用),我们需要的是超类型原型的副本。本质:使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
function Super(b){
this.b = b;
this.fun = function(){}
}
Super.prototype.c = function(){console.log(1111)}
Super.prototype.name="张三";
function f1(){
}
//寄生:基本思想:创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象
//缺点:不能做到函数复用导致降低效率
var f = new f1();
//f.c= Super.prototype.c;
f.prototype= Super.prototype;
//f1.prototype=Super.prototype;
function Foo(a,b){
this.a = a;
Super.call(this,b);
}
Foo.prototype =f;
var foo1 = new Foo(1,2);
console.log(foo1.prototype.c());
//父类的原型方法
Animal.prototype.eat = function () {
return this.name + "吃饭";
}
function Cat(name, sex) {
Animal.call(this, name, sex)
}
// Cat.prototype=new Animal("小花","公");
var cat = new Cat("小花", "公");
cat.super = Animal.prototype;
console.log(cat.super.eat.call(cat));
继承时有些模式 拿不到父类的原型方法和属性 考虑寄生模式