浅谈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请求等 ...
随机推荐
- android apk 的root 权限和USB adb 权限的差别
USB adb 权限是指,当adb 连接手机时,手机中的守护进程adbd 的权限为root 权限,从而它的子进程也具有root 权限.通常假设adb shell 看到是: Android 4.0 以后 ...
- 基于Metronic的Bootstrap开发框架经验总结(17)-- 使用 summernote插件实现HTML文档的编辑和图片插入操作
在很多场合,我们需要在线编辑HTML内容,然后在页面上或者其他终端上(如小程序.APP应用等)显示,编辑HTML内容的插件有很多,本篇介绍基于Bootstrap的 summernote插件实现HTML ...
- Node.js显示页面
首先我们先要下载并安装Nodejs,然后进入Node.js中安装supervisor, npm -g install supervisor -g表示全局模式 (无论windows哪一个用户登陆都可以使 ...
- Handlebars 新手使用
昨天抽空看了一下关于Handlebars的 基础使用, 从开始写asp.net 用视图引擎,到写web 的时候 ,都是 用AJAx 来接受并分析数据,然后用 拼接的方式,或者追加的方式来实现在 页 ...
- Java之路上,让我们Stand Up Again
在开始之前,先发表一下个人想法吧. 在读书的时候每天忙的不可开交,也就没有了所谓的自由,突然参加工作,传统的朝八晚五,标准的八小时工作制,每天都是两点一线,工作中涉及商业机密,公司的东西也不能带回家, ...
- 56、jsのBOM对象与DOM对象
javascript的Bom和Dom对象使我们学习的重点,这篇随笔可以重点阅读 一.BOM对象 1.window对象 所有浏览器都支持 window 对象.概念上讲.一个html文档对应一个windo ...
- LR接口压力测试实战(限量抢红包接口)
一.业务描述:微信群中,运营人员放出活动链接,用户单击活动链接进入活动页面如下图,用户输入手机号抢红包(红包数量有限) 二.接口测试代码 Action() { lr_rendezvous(" ...
- JAVA NIO学习一:NIO简介、NIO&IO的主要区别
在前面学习了IO之后,今天我们开始进入NIO学习环节,首先我们会NIO做一个简单的介绍,让大家认识NIO,然后会和IO进行一个对比认识进行区分.好了,下面我们就开始学习: 一.NIO简介 1.概述 从 ...
- Tableau Desktop 10.4.2 的安装和激活
在安装之前,首先我们要弄清楚Tableau是个什么鬼东西,我们为什么需要安装这款软件? Tableau将数据运算与美观的图表完美地嫁接在一起.它的程序很容易上手,各公司可以用它将大量数据拖放到数字&q ...
- Java 本地开发环境搭建(框架采用 Spring+Spring MVC+Hibernate+Jsp+Gradle+tomcat+mysql5.6)
项目搭建采用技术栈为:Spring+Spring MVC+Hibernate+Jsp+Gradle+tomcat+mysql5.6 搭建环境文档目录结构说明: 使用Intellj Idea 搭建项目过 ...