注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

梦幻雪冰

技在手,能在身,思在脑,从容过生活——陈能堡

 
 
 

日志

 
 

JavaScript 高级开发-继承  

2014-10-26 16:57:06|  分类: JavaScript |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

JavaScript 高级开发-继承

欢迎学习交流-梦幻雪冰
【1】了解继承
在oo(面向对象)语言中,大家都知道的一个概念--继承,继承可以分为两种:第一:接口继承(只有继承方法签名或或者叫方法的地址,告诉你这个函数叫什么,里面是没有执行代码语句);第二:实现继承(有函数体的方法),在JavaScript中只能支持实现继承,实现继承其实主要靠的是原型链来实现。

【2】原型链的基本原理
利用原型让一个引用类型继承另一引用类型的属性和方法。

接下来来写一个例子看看,原型链到底是什么东东?
JavaScript 高级开发-继承 - 梦幻雪冰 - 梦幻雪冰欢迎学习交流-梦幻雪冰
function Animal(){
     // 对象属性
     this.animalName = "动物";
}

Animal.prototype.say = function(){
     console.log(this.animalName);
}

function Peo(){
     this.peoName = "人类";
}
//实现继承
Peo.prototype = new Animal();
Peo.prototype.sayPeo = function(){
     console.log(this.peoName);
}

var peo = new Peo();
peo.sayPeo();
peo.say();
console.log(peo.constructor == Peo);
console.log(peo.constructor == Animal);
注:constructor是构造函数创建的实例都有一个构造函数的属性,用来标识对象的类型。
【输出】人类 动物     false true

画图辅助理解:
JavaScript 高级开发-继承 - 梦幻雪冰 - 梦幻雪冰

【结果】Peo的实例对象指向的是它的原型对象,Peo的原型对象已经指向了Animal的原型对象了,因为Animal的实例对象赋值给Peo原型对象了,实例对象指向的是原型对象,所以Peo的原型对象指向的是Animal的原型对象。还有一点的是animalName是实例属性(位于实例当中),所以才会存在与Peo原型对象里面(Animal实例赋值给Peo原型对象了,所以才有那个对象属性)。那么现在Peo的实例对象属于Peo的类型还是Animal的类型?因为Peo原型对象里面的constructor属性已经被重写了,所以constructor已经指向了Animal的构造函数了。

【3】默认原型
所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。

画图辅助理解:
JavaScript 高级开发-继承 - 梦幻雪冰 - 梦幻雪冰

 【结论】从图中可以得出Peo继承了Animal,Animal继承了Object。

休息一下啦
JavaScript 高级开发-继承 - 梦幻雪冰 - 梦幻雪冰欢迎学习交流-梦幻雪冰

【4】子类添加新方法
子类型添加方法两种情况:一种是重写父级的方法(超类型),另外一种添加父级没有的方法
function Animal(){
     // 对象属性
     this.animalName = "动物";
}

Animal.prototype.say = function(){
     console.log(this.animalName);
}

function Peo(){
     this.peoName = "人类";
}
// 继承Animal
Peo.prototype = new Animal();

// 重写超类的方法(父类的方法)
Peo.prototype.say = function(){
     console.log("重写的方法:" + this.animalName);
}

// 添加新方法
Peo.prototype.sayPeo = function(){
     console.log(this.peoName);
}

// 创建Peo实例
var peo = new Peo();
peo.sayPeo();
peo.say();
【输出】人类 重写的方法:动物

用另外一种方法进行添加方法
function Animal(){
     // 对象属性
     this.animalName = "动物";
}

Animal.prototype.say = function(){
     console.log(this.animalName);
}

function Peo(){
     this.peoName = "人类";
}
// 继承Animal
Peo.prototype = new Animal();

// 用对象的写法进行重写
Peo.prototype = {
     sayName : function(){
          console.log("人类");
     }
}

var peo = new Peo();
peo.sayName();
peo.say(); // 直接报错
【输出】人类 报错

画图辅助理解:
JavaScript 高级开发-继承 - 梦幻雪冰 - 梦幻雪冰
 
【结论】重写的原型包含的是一Object的实例,而不是包含Animal的实例。所以Peo与Animal已经没有关系了,所以直接报错了。简单的来说原型链已经断开了。
 
【5】借用构造函数继承
从原型链中出现了两个问题:一:原型对象里面的属性会被所有实例所共享(构造函数的实例指向原型)
                                          二:在子类型创建的实例无法给超类(父级)的构造函数传递参数

 解决办法:借用构造函数(经典继承)
function Animal() {
     this.name = "动物";
}
function Peo() {
     // 继承了Animal
     Animal.call(this);
}

var peo1 = new Peo();
console.log(peo1.name);
var peo2 = new Peo();
console.log(peo2.name);
【输出】动物 动物
【结论】利用构造函数实现实例属性的继承

继续优化,进行参数的传递
function Animal(name) {
     this.name = name;
     // 查看该函数的this
     console.log(this);
}
function Peo(name) {
     // 继承了Animal
     Animal.call(this, name);
}
var peo1 = new Peo("动物");
console.log(peo1.name);
var peo2 = new Peo("人类");
console.log(peo2.name);
【结论】如果仅仅的使用借用构造函数的话,就无法避免掉构造函数的问题------方法都必须在构造函数里面定义,无法重复利用的问题。还有一点就是在超类型(父级)原型中定义的方法,子类型是无法调用的到。

【6】组合继承
将原型链和借用构造函数组合在一起,利用原型链实现方法的继承,而通过借用构造函数实现实例属性的继承。

// 超类型

function Animal(name, color) {
     this.name = name;
     this.color = color;
}

Animal.prototype.say = function() {
     console.log(this.name + " " + this.color);
}

// 子类型
function Peo(name, color, age) {
     // 继承
     Animal.call(this, name, color); // 第二次调用

     this.age = age;
}

// 继承
Peo.prototype = new Animal(); // 第一次调用

Peo.prototype.sayAge = function() {
     console.log(this.age);
}

// 创建实例
var peo1 = new Peo("小小", "白色", 22);
peo1.say();
peo1.sayAge();
var peo2 = new Peo("东东", "黑色", 20);
peo2.say();
peo2.sayAge();
console.log(peo2.say == peo1.say);
【输出】小小 白色 22 东东 黑色 20 true
【结论】组合继承避免了原型链和借用构造函数的缺陷,也是在JavaScript中最常用的继承模式。在组合模式中会发生两次调用超类型的构造函数:第一次调用是在创建Peo实例,Peo的原型对象会得到两个属性;第二次调用是在子类型构造函数内部。

欢迎学习交流-梦幻雪冰


欢迎学习交流——梦幻雪冰独行冰海@font-face中iefix的详解 - 梦幻雪冰 - 梦幻雪冰
HTML5学堂贴吧——HTML5学堂
HTML5学堂微博——HTML5学堂
  评论这张
 
阅读(141)| 评论(2)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017