浅谈JavaScript的面向对象程序设计(四)
本文继续讲解JavaScript的面向对象程序设计。继承是面向对象语言中的一个基本概念,面向对象语言支持两种继承实现方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。但是在JavaScript中函数时没有签名的,所以无法实现接口继承。JavaScript支持实现继承,而且其实现继承主要是通过原型链继承的。
- 原型链
JavaScript中有原型链的概念,并将原型链作为实现继承的主要方法。基本实现思想是让一个函数的原型继承另外一个函数的原型的属性和方法。每一个函数都有一个原型对象,原型对象包含一个指向构造函数的指针,实例包含一个指向原型对象的指针。原型链的概念就是,一个原型对象指向另一个函数的原型,同样另一个函数的原型又指向其他函数的原型,层层递进,就构成了原型链。
function SuperType(){
}
function SubType(){
}
SubType.prototype=new SuperType();
function ExtendType(){
}
ExtendType.prototype = new SubType();
上面的代码展示了原型链的概念,ExtendType的原型指向了SubType实例,SubType的原型指向了SuperType实例,SuperType的原型指向了Object的原型。这样就形成了一个原型链。原型链本质上是扩展了前面介绍的原型搜素机制。当访问实例的属性或者方法时,首先搜索实例的属性或者方法,再搜索实例的原型。通过原型链,可以一直向上搜索,直至搜索到Object的原型。
前面也简单地介绍了确认原型的方法。
var extendtype = new ExtendType();
console.log(extendtype instanceof Object);
console.log(extendtype instanceof SubType);
console.log(extendtype instanceof SuperType);
上面的代码中2、3、4行都输出true,这说明extendtype中能找到函数的原型。也可以通过另外一种方法实现原型的判断,就是通过原型的isPrototypeOf方法。
console.log(Object.prototype.isPrototypeOf(extendtype));
console.log(SubType.prototype.isPrototypeOf(extendtype));
console.log(SuperType.prototype.isPrototypeOf(extendtype));
上面的代码通过isPrototypeOf方法来判断实例的类型。同样,输出都是true。
通过原型链在JavaScript中实现的继承依然存在一定的问题。原型链会将实例中的所有属性都共享,但是我们在构造函数中定义属性,二不在原型中定义属性就是为了不共享属性
function Super(){
this.colors=["green"];
}
function Sub(){
}
Sub.prototype= new Super();
var sub = new Sub();
sub.colors.push("red");
console.log(sub.colors.toString());//green,red
var sub2 = new Sub();
console.log(sub2.colors.toString());//green.red
上面的代码定义两个对象super和sub,sub的原型继承了super的实例。我们创建了sub的两个实例,对其中的一个实例colors的属性添加了一个元素,但是我们发现两个实例的属性都改变了。因为该两个实例的colors属性都指向super中的属性。
- 借用构造函数
借用构造函数的思想就是在子类型的构造函数中调用父类的构造函数,可以通过apply或者call调用父类构造函数。
function Super(){
this.colors=["green"];
}
function Sub(){
Super.call(this);
}
var sub = new Sub();
sub.colors.push("red");
console.log(sub.colors.toString());//green,red
var sub2 = new Sub();
console.log(sub2.colors.toString());//green
上面的代码在子类的函数中调用了父类的构造函数,通过call。同时,我们实例化了两个子类对象,发现sub的操作并没有影响sub2的结果。每次实例化都会调用父类的构造函数,这样每个sub都有自己的colors属性。
同时,通过借用构造函数,我们还能传递参数。
function Super(name){
this.colors=["green"];
this.name=name;
}
function Sub(name){
Super.call(this,name);
}
var sub = new Sub("hehe");
sub.colors.push("red");
console.log(sub.name);//hehe
var sub2 = new Sub("haha");
console.log(sub2.name);//haha
上面的代码,我们通过构造函数传递了参数,并通过call方法传递参数给父类的构造函数。借用构造函数和构造函数模式创建对象拥有同样的问题,方法和属性都在构造函数中定义,因为函数无法复用。也无法判断函数的类型。
- 组合式继承
组合继承是指将原型链和构造函数的技术组合在一起。它的思路是通过原型链实现属性和方法的继续,通过借用构造函数模式实现实例属性的继承。这样在原型链上实现方法,保证函数的复用,同时又保证每个实例有自己的属性。
function Super(name){
this.name=name;
}
Super.prototype.getName=function(){
return this.name;
}
function Sub(name,age){
Super.call(this,name);
this.age=age;
}
Sub.prototype= new Super();
var sub = new Sub("haha",18);
console.log(sub.getName());//haha
console.log(sub.age);//
var sub2 = new Sub("hehe",19);
console.log(sub2.getName());//hehe
console.log(sub2.age);//
上面的代码中Super定义了一个属性name和一个原型方法getName,sub定义了一个实例属性age。sub继承了super的实例。也就是sub用super的原型方法,同时能够调用super的实例属性。在后面定义了两个sub实例,他们是不同的实例,拥有不同的实例属性,但是他们共享了原型方法。
组合继承避免了原型链和构造函数的缺陷,是一种常用的继承实现方法。
- 原型式继承
克罗克福德提出了原型式继承的方法。他的方法是借助原型基于已有的对象创建新的对象,同时还不必因此创建自定义类型。
function create(o){
function F(){};
F.prototype=o;
return new F();
}
在create函数内部,先创建了零时行的函数F,并将F的原型指向参数o,参数o是另一个对象的原型,最后返回F的实例,并且该实例继承了传递进行来的对象的原型。
function create(o){
function F(){};
F.prototype=o;
return new F();
}
var Person={
"name":"haha",
getName:function(){
return this.name;
}
}
var oneperson=create(Person.prototype);
oneperson.name="hehe";
console.log(oneperson.name);//hehe
var twoperson = create(Person.prototype);
twoperson.name="jack";
console.log(twoperson.name);//jack
上面的代码,基于create函数创建了两个对象,这两个对象继承了Person。这就意味着Person中的属性和方法,oneperson中同样拥有。ECMAScript5中定义了新的方法Object.create()方法,该方法有两个参数,一个参数是一个对象原型,另一个参数是需要生成的新属性。与上面的方法类似。
- 寄生式继承
寄生式继承与寄生式函数的工厂模式类似,也是创建一个用于封装继承过程的函数。在函数内部以一定的方式增强对象,最后返回对象。
function create(o){
function F(){};
F.prototype=o;
return new F();
}
function createPerson(o){
var f=create(o);
o.sayHi=function(){
console.log("hi");
}
return o;
}
var Person={
name:"haa",
age:"8"
}
var one=createPerson(Person);
上面的one不仅继承了person的属性,同时还拥有增强属性sayHi。
- 寄生组合式继承
前面说过最常用的继承方式是组合式继承,但是组合继承,不论什么情况,都要父类构造函数两次。第一次是在子类继承父类的实例时候,第二次是子类实例化过程中。
寄生组合式继承,通过借用构造函数来继承属性,通过原型链来继承方法。使用寄生式继承来继承父类的原型,不必通过实例化来继承父类,这样减少了调用父类构造函数的次数,只用调用一次。
function create(o){
function F(){};
F.prototype=o;
return new F();
}
function SuperType(name){
this.name=name;
}
function Sub(name,age){
SuperType.call(this,name);
this.age=age;
}
Sub.prototype=create(SuperType.prototype);
Sub.prototype.getName=function(){
return this.name;
}
var sub = new Sub("haha",19);
console.log(sub.getName());//
var sub2 = new Sub("hehe",18);
console.log(sub2.getName());//hehe
浅谈JavaScript的面向对象程序设计(四)的更多相关文章
- 浅谈JavaScript的面向对象程序设计(三)
前面已经对JavaScript的面向对象程序设计作了简单的介绍,包括了对象的属性.对象的工厂模式.构造函数和原型等.通过介绍,这些创建对象的方法依然有不少优化和改进的地方. 组合使用构造函数模式和原型 ...
- 浅谈JavaScript的面向对象程序设计(一)
面向对象的语言有一个标志,他们都有类的概念,通过类可以创建多个具有相同属性和方法的对象.但是JavaScript中没有类的概念,因此JavaScript与其他的面向对象语言还是有一定区别的.JavaS ...
- 浅谈JavaScript的面向对象程序设计(二)
前面介绍通过Object构造函数或者字面量创建单个对象,但是通过这个的方法创建对象有明显的缺点:调用同一个接口创建多个实例,会产生大量的重复代码.怎么样解决? 工厂模式 工厂模式是软件工程领域经常使用 ...
- 浅谈JavaScript的面向对象和它的封装、继承、多态
写在前面 既然是浅谈,就不会从原理上深度分析,只是帮助我们更好地理解... 面向对象与面向过程 面向对象和面向过程是两种不同的编程思想,刚开始接触编程的时候,我们大都是从面向过程起步的,毕竟像我一样, ...
- 浅谈javascript的面向对象思想
面向对象的三大基本特性 封装(把相关的信息(无论数据或方法)存储在对象中的能力) 继承(由另一个类(或多个类)得来类的属性和方法的能力) 多态(一个对象在不同情况下的多种形态) 定义类或对象 第一种: ...
- 浅谈JavaScript浮点数及其运算
原文:浅谈JavaScript浮点数及其运算 JavaScript 只有一种数字类型 Number,而且在Javascript中所有的数字都是以IEEE-754标准格式表示的.浮点数的精度问题 ...
- 浅谈JavaScript中的正则表达式(适用初学者观看)
浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...
- [转载]浅谈JavaScript函数重载
原文地址:浅谈JavaScript函数重载 作者:ChessZhang 上个星期四下午,接到了网易的视频面试(前端实习生第二轮技术面试).面了一个多小时,自我感觉面试得很糟糕的,因为问到的很多问题都 ...
- 浅谈javascript函数节流
浅谈javascript函数节流 什么是函数节流? 函数节流简单的来说就是不想让该函数在很短的时间内连续被调用,比如我们最常见的是窗口缩放的时候,经常会执行一些其他的操作函数,比如发一个ajax请求等 ...
随机推荐
- 4、libgdx应用框架
(原文:http://www.libgdx.cn/topic/29/4-libgdx%E5%BA%94%E7%94%A8%E6%A1%86%E6%9E%B6) 模块 作为核心.libgdx提供了六个接 ...
- hdu1181 变形课(vector容器+dfs)
变形课 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others) Total Submi ...
- Swift入门(五)——数组(Array)
集合 集合的定义 Swift中提供了两种数据结构用于存放数据的集合,各自是数组(Array)和字典(Dictionary). 他们的主要差别在于数组中的元素由下标确定.而字典中的数据的值由数据的键(K ...
- (转)java中的方法区
首先要说明的是,此文章转载自 http://blog.csdn.net/zzhangxiaoyun/article/details/7518917 谢谢作者.是本人认为对方法区解释得比较清楚的一篇文章 ...
- cs231n --- 3 : Convolutional Neural Networks (CNNs / ConvNets)
CNN介绍 与之前的神经网络不同之处在于,CNN明确指定了输入就是图像,这允许我们将某些特征编码到CNN的结构中去,不仅易于实现,还能极大减少网络的参数. 一. 结构概述 与一般的神经网络不同,卷积神 ...
- mybatis框架(5)---动态sql
那么,问题来了: 什么是动态SQL? 动态SQL有什么作用? 传统的使用JDBC的方法,相信大家在组合复杂的的SQL语句的时候,需要去拼接,稍不注意哪怕少了个空格,都会导致错误.Mybatis的动态S ...
- 从初识Maven到使用Maven进行依赖管理和项目构建
前些天就安装了Maven,以备自己以后整合项目用,尤其是我们的ssh,ssm项目.想必好多人在开始的时候并不清楚Maven是什么,它能够帮助我们干什么. 所以在学习Maven之前我们一定要知道它是什么 ...
- (转)为Xcode添加删除行、复制行快捷键
转摘链接:http://www.jianshu.com/p/cc6e13365b7e 在使用eclipse过程中,特喜欢删除一行和复制一行的的快捷键.而恰巧Xcode不支持这两个快捷键,再一次的恰巧让 ...
- php项目报错 Warning: session_start(): open(D:/software/wamp/wamp/tmp\sess_msrjot7f32ciqb1p2hr4ahejg4, O_RDWR) f
今天一个php项目报错: Warning: session_start(): open(D:/software/wamp/wamp/tmp\sess_msrjot7f32ciqb1p2hr4ahejg ...
- Java面试题汇总
第一阶段:三年我认为三年对于程序员来说是第一个门槛,这个阶段将会淘汰掉一批不适合写代码的人.这一阶段,我们走出校园,迈入社会,成为一名程序员,正式从书本 上的内容迈向真正的企业级开发.我们知道如何团队 ...