我们在学习编程时,避免不了会接触一个概念,叫:面向对象编程(Object-oriented programming,缩写:oop) (不是搞对象那个对象哈),其实我们的编程方式,不止有面向对象,还有 面向过程编程面向流编程面向函数编程面向接口编程 等。作为一名一直混迹在前端的小菜鸟,今天就来跟大家深入的探讨一下 JavaScript面向对象。作为程序员,我们多多少少都会接触自己擅长语言之外的编程语言,比如我作为一名前端,同时我还会 Java,从这两个语言本身出发的话,我们会发现这两种语言的 面向对象 存在着一丝丝的不同,到底哪里不同呢?我们今天就拿这两种语言对比着来,拿具体的实例看一下,到底什么叫 面向对象编程

现在很多文章都会讲 面向对象三大特性面向对象七原则设计模式 等概念,今天这篇文章不准备讲这些概念,从实例出发,理解 面向对象 是什么,如何做 面向对象 程序设计。

我们在深入探讨 面向对象 之前,我们先来复习一下 面向过程编程,这里可能有人会问了,不是讲 面向对象 吗?为什么还要讲 面向过程 呢?主要是因为,面向过程编程 是软件思想中的鼻祖。面向过程编程 还是很好理解的,因为它是一种以 过程 作为中心的编程思想,其中 过程 的含义就是 完成一件事情的步骤

面向过程 其实是一种 机械的思想,它就像流水线一样,一个阶段衔接一个阶段,每个阶段都有自己的输入、处理、输出,而在流水线上流动的就是我们的原料或者中间产品,每个阶段都有一个机械进行处理,最后的输出就是我们的产品。

在运用 面向过程 的方法时,你也需要设计这样一条程序:将程序划分为不同的阶段,设计好各个阶段如何衔接,然后定义好每个阶段需要处理的数据。

在实际开发中,我们会把需求拆成一个一个的命令,然后串起来交给计算机去执行。举个例子,有个需求是:在淘宝给女朋友买口红,那么程序员接到这个命令,会列出如下几个步骤:

  • 打开淘宝
  • 买口红
  • 送女朋友

上面的每一个步骤,程序员都会用一个 函数方法 来实现,而 函数方法 是一些代码的集合体,每个 函数方法 可以实现一个功能,那么根据上述需求,我们可能会定义如下的函数:

  • openTaoBao();
  • buyLipstick();
  • sendGrilFriend();

那么程序就会顺序调用了。需求完成,顺利交工。但是,你觉得这样就算结束了么?No。产品经理说:"这才刚刚开始哦~~~"。

在开始介绍 面向对象 之前,我们先来简单概述一下,什么是 对象对象 是一个自成一体的实体,它仅包含属性和行为,不含任何其他内容。与面向过程的方法相比,面向对象 不在局限于计算机的机器本质,而更加侧重于对现实世界的 模拟。在 面向过程 的方法中,有一套设计严格的操作顺序,有一个类似 中央控制器 的角色来进行统一调度;而 面向对象 的方法中,并没有明确的 中央控制器 的角色,也不需要指定严格的操作循序,而是设计了很多 对象,并且指定了这些 对象 需要完成的任务,以及这些 对象 如何对外界的刺激做出反应。

如果说 面向过程 像一条流水线,那么 面向对象 就像是一个篮球队。没有哪个人能够在一场比赛开始的时候,就精确指定每个队员的每一次跑动、每一次传球、每一次投篮...而是要指定队员的角色(前锋、中锋、后卫等等),然后由队员们自己根据情况做出反应。所以说,世界上可以有两个一模一样的生产线,但绝对不会存在两场一模一样的比赛。

简单介绍了一下 对象,现在让我们回到上面的例子。接下来,产品经理又提了需求:

  • 在京东给女朋友买防晒霜
  • 在唯品会给麻麻买貂
  • 在苏宁易购给爸爸买刮胡刀
  • ...

如果我们还是用 面向过程 的方法,每次需求的变更,程序员就要把整个系统通读一遍,找出可用的函数(如果没有就再定义一个),最后依次调用它们。最后系统越来越杂乱无章难以管理,程序员不堪重负,纷纷操起刀走上了不归路[笑哭]...

面向对象 从另一个角度来解决这个问题,它抛弃了函数,把 对象 作为程序的基本单元。那么 对象 到底是个什么东西呢?对象 就是对 事务的一种 抽象 描述。其实现实中的 事务,都可以用 数据能力 来描述。比如我要描述一个人,数据 就是他的年龄、性别、身高、体重等,能力 就是他能做什么工作,承担什么样的责任。描述一台电视,数据 就是它的屏幕尺寸、亮度,能力 就是播放青春偶像剧。

面向对象 的世界里,到处都是 对象对象 不光有 数据能力 ,还可以接受命令。例如,你可以让 这个对象 吃猫粮,就可以把 吃猫粮 的命令发给 让其执行(虽然傲娇的猫咪并不能听你的话吧[笑哭],这里只是举个例子),然后我们就实现了 猫吃猫粮 的需求。

现在 对象 有了,那接下来该如何进行 面向对象 的编程呢?其实很简单,我们依次向不同的 对象 发送命令就可以了。回到上面的例子,我们用 面向对象 来实现;先定义一个 app 对象,它的 数据 就是商城名称、商品类型等,能力 就是打开、关闭;还有一个 对象,它的 数据 是姓名、性别、称谓等,能力 就是买口红、送口红。然后我们依次下达命令:

  • 向app下达 打开 的命令;
  • 向人下达 买口红送女朋友 的命令;
  • 向app下达 关闭 的命令。

其实,我们创建的对象,应该是刚刚好能做完它能做的事情,不多做,也不少做。多做了容易耦合,各种功能杂糅在一个对象里。比如我有一个对象叫 汽车,可以 载人,现在的需求是要实现 载人飞行,就不能重用这个 对象,必须新定义一个对象 飞机 来做。如果你给 汽车 插上了翅膀,赋予了它 飞行的能力,那么新来的同学面对你的代码会莫名其妙,无从下手。

接下来,我们来看一下,上面的例子用代码是如何实现的:

  1. 首先要创建一个 App 的对象,里面包含商城名称的数据,打开和关闭的能力:
 function App(shopName) {
this.shopName = shopName;
} App.prototype.open = function () {
return `打开${this.shopName}`;
}; App.prototype.close = function () {
return `关闭${this.shopName}`;
};
  1. 接着我们创建一个 的对象,里面包含称谓的数据,买和送的能力:
 function Person(title) {
this.title = title;
} Person.prototype.buy = function (product) {
return `买${product}`;
}; Person.prototype.send = function () {
return `送给${this.title}`;
};
  1. 最后我们实例化对象,然后聚合我们需要的功能:
 const app = new App('淘宝');
console.log(app.open());
const person = new Person('女朋友');
console.log(person.buy('口红'));
console.log(app.close());
console.log(person.send());
  1. 我们来看一下最后的执行结果:

基于上面的例子,我们可以看到,JavaScript面向对象 是基于 原型 的,也就是 prototype,而 Java 呢?Java 是基于 的,也就是所谓的 class。其实不管语言对于 面向对象 是基于什么的,从概念上讲,大家都是一样的,只是我们的实现方式不同。

在这里,我就不举 Java 基于 面向对象 是如何实现上述实例的了,因为这篇文章讲的就是 JavaScript [斜眼笑],想看 Java 的可以根据上述的文字描述自己实现一下哈,博主在这里就皮一下[笑哭]。

抽象

抽象 的中文概念非常形象,简单来说就是 抽取出来比较像的部分。那么,在 面向对象 的领域里,抽取什么东西是比较像的部分?我们画个图来看一下 抽象 是个什么东东:

这里的抽象分为两个层次:

第一个层次:对象是抽象成集合(类)
例如:西瓜苹果 抽象成 水果,这一层的 抽象 主要是将 属性类似 的对象抽象出来。

注意:这里的 属性类似 是指 属性类别 一致,而属性的取值是不一样的。例如,将"西瓜"和"苹果"都抽象成"水果",那么其属性有颜色、重量、味道等等,但"西瓜"和"苹果"的这些属性取值肯定是不同的。

第二个层次(或更高层次):将对象抽象为超集合(超类,或者说父类,就是更高一级的集合或者类)
例如:水果蔬菜 抽象成 食物,这一层的抽象主要是将 行为类似 的抽象成父集合(父类)。

注意:这里是 行为类似,而不是第一层抽象的那样 属性类似,因为在 面向对象 领域,行为一致的话就认为是同一类的,当然也不能是完全不同,完全不同的话就没有相似点,也就无法抽象成类了,所以这一层抽象的重点是 相似

在实际应用中,抽象的层次是不限的,根据业务需要,或者不同的观察角度,可以抽象出很多层。

抽象的作用

抽象 并不是面向对象领域特有的概念和方法,在我们的日常生活和学习中,抽象 最主要的作用是 划分类别,而 划分类别 的主要目的其实还是关注隔离点,降低复杂度。所以,抽象是面向对象领域里面发现集合(类)的主要方法

在JavaScript中,抽象 是允许模拟工作问题中通用部分的一种机制。这可以通过继承(具体化)或组合来实现。JavaScript通过 继承 实现 具体化,通过让类的实例是其他对象的属性值来实现组合。
JavaScript Function类 继承自 Object类(这是典型的具体化)Function.prototype 的属性是一个 Object实例(这是典型的组合)

多态(polymorphism)

引用 MDN web docs 中的一段话来描述一下 JavaScript多态

就像所有定义在原型属性内部的 方法属性 一样,不同的类可以定义具有相同名称的方法;方法是作用于所在的类中。并且这仅在这两个类不是父子关系时成立(继承链中,一个类不是继承自其他类)。

[笑哭]大家看完这段话之后,是不是觉得很懵,这是在说什么啊,什么类,什么继承。不着急哈,接下来我会详细解释一下在 JavaScript 中,多态究竟是怎么样的存在哈...

polymorphism,翻译成中文:多态性,我们从字面意思上就可以看出,多态 就是 多种形态 的意思。但仔细探究一下:多种形态 其实还是没法很好的理解,不同的人也还是有不同的理解。

动画片看得多的同学可能会以为:多种形态,就是很多种变身,就像孙悟空72变一样,一会儿可以变成房子,一会儿可以变成牛魔王;
擅长打扮的美女可能会以为:多种形态,其实就是换不同的衣服嘛,一会儿文艺小清新打扮,一会儿高贵典雅的贵妇装束;
学院派技术宅男可能会以为: 多种形态,其实就是多种状态啦,比如说TCP协议栈有XX种状态...

可能还有很多其它各种各样的理解,但在 面向对象 领域,这些理解都不正确,多态不是变身、换装、状态变化,而是多胎...

哇!!博主你打错字了,怎么可能是 多胎呢?这是什么意思啊?

其实,多胎 在这里也是一个形象的说法,在 面向对象 领域,多态 的真正含义是:使用指向父类的指针或者引用,能够调用子类的对象

我要是在这里引用 Java 代码,会不会引起公愤[笑哭],还是乖乖的用 JavaScript 来写个 多态 的例子:

  1. 首先建一个 Person 对象:
 // 定义Person构造器(类)
function Person(personName) {
this.personName = personName;
} // 在Person.prototype中加入study方法
Person.prototype.study = function () {
return `${this.personName}学习语文`;
};
  1. 然后创建一个 Boy 对象,并且继承自 Person 对象,修改原先 Person 对象中的方法:
 1 // 定义Boy构造器(类)
function Boy(personName) {
// 调用父类构造器,确保"this"在调用过程中设置正确
Person.call(this, personName);
} //建立一个由Person.prototype继承而来的Boy.prototype对象
Boy.prototype = Object.create(Person.prototype); // 设置"constructor"属性指向Boy
Boy.prototype.constructor = Boy; // 更换"study"方法
Boy.prototype.study = function () {
return `${this.personName}学习数学`;
};
  1. 再然后,创建一个 Girl 对象,也让它继承自 Person 对象,继续修改原先 Person 对象中的方法:
 // 定义Girl构造器(类)
function Girl(personName) {
Person.call(this, personName);
} //建立一个由Person.prototype继承而来的Girl.prototype对象
Girl.prototype = Object.create(Person.prototype); // 设置"constructor"属性指向Girl
Girl.prototype.constructor = Girl; // 更换"study"方法
Girl.prototype.study = function () {
return `${this.personName}学习英语`;
};
  1. 创建一个执行函数:
 // 这个参数就是"多态"的具体表现形式
const test = function (person) {
// 在调用person.study()的时候,函数并不知道person究竟是Boy,还是Girl,只知道是个对象
console.log(person.study());
}; // 执行test方法
test(new Boy('Tom'));
test(new Girl('Jenny'));
  1. 最后我们看一下执行结果:

嗯,没错,是我们想要的结果[嘿嘿]。那接下来,我们在来看一下,如果不用 多态,上述的例子要怎么写。

  1. 好,先创建一个执行对象那个:
 // 定义一个执行的构造器(类)
function Test() {} // 在Test.prototype原型中加入boyStudy方法
Test.prototype.boyStudy = function (boy) {
console.log(boy.study());
}; // 在Test.prototype原型中加入girlStudy方法
Test.prototype.girlStudy = function (girl) {
console.log(girl.study());
};
  1. 在创建一个 Boy 对象:
 function Boy(boyName) {
this.boyName = boyName;
} Boy.prototype.study = function () {
return `${this.boyName}学习数学`;
};
  1. 在创建一个 Girl 对象:
 function Girl(girlName) {
this.girlName = girlName;
} Girl.prototype.study = function () {
return `${this.girlName}学习英语`;
};
  1. 最后,我们调用执行对象,输出这两个对象的数据:
 const test = new Test();

 test.boyStudy(new Boy('Tom'));

 test.girlStudy(new Girl('Jenny'));

当然最后的执行结果肯定是一样的,那让我们来看一下,这两种写法到底有什么区别:

  • 首先,最开始的那个例子,我们用了个 test 函数,注释也写了,不需要关心对象具体是哪个,只要对象包含需要调用的方法就OK;
  • 而第二个例子呢?我们仔细看一下,第二个例子现在看起来很清晰,但是不利于扩展,为什么?关键点在执行函数中,如果我要是在加了 女人男人 这两个对象的话,那是不是还得在 Test 对象里面在添加两个对应的执行方法?答案是肯定的,不然没地方执行呀。
  • 所以说,这就是 多态 的特点。

有兴趣的同学还可以用 es6 语法的 classextends 来写一下上述的例子,我这里就不在赘述了。

我们说了这么多,主要是想讲述一下在 JavaScript 中,是怎么体现这些思想的,我最想说的一句话就是:JavaScript 是基于 原型 的语言,也希望大家能一直记住这句话。

而 Java 呢,是基于 类(class) 的语言,这两种语言从语法上就有本职的区别,但是概念性的东西,是不会变的。我们应该抛开语言层面,更进一步的去学习面向对象的概念,然后在从语言上下手,学习如何实现这一概念。

啊哈,对了,突然想到,虽然现在对于前端来说,JavaScript 挺重要的,但是我们大多数同学在开发时,会用到三大框架的其中之一(react、vuee、angular),也有可能都用过,我们大多数人把关注点都放在了 JavaScript,而忽略了我们的 html + css 也是有 面向对象 概念的。今天就拿 vue 中的组件概念,来简单说说 模板 是如何实现 面向对象 的。

不知道用 vue 做过开发的同学们,记不记得组件有个概念叫 动态组件[斜眼笑]。对,就是那个 <component></component>,需要通过 is 属性来加载不同的组件。这里就不在具体举例子讲这个东西怎么用了,但是它就是 多态 的一种的实现形式,component 不会关心你的组件都有什么(作用相当于上述js例子的test函数),知道你传过来的数据,我能匹配上,找到你想要的那个结果就好了。官方举的例子是关于 tab 进行动态切换时,不管加几个标签,对本身功能并不会有影响,只需要多建几个模板就好了。

好了,就讲这么多吧,对 Java 感兴趣的同学,可以根据上述的例子,用 Java 来写一下,体验一下 面向对象多态 的快感,啊哈哈~~~

深入理解 JavaScript 面向对象的更多相关文章

  1. 深入理解Javascript面向对象编程

    深入理解Javascript面向对象编程 阅读目录 一:理解构造函数原型(prototype)机制 二:理解原型域链的概念 三:理解原型继承机制 四:理解使用类继承(继承的更好的方案) 五:建议使用封 ...

  2. 全方位深入理解JavaScript面向对象

    JavaScript面向对象程序设计 转载:https://blog.csdn.net/lihangxiaoji/article/details/79753473#72__871 本文会碰到的知识点: ...

  3. 深入理解 Javascript 面向对象编程

    一:理解构造函数原型(prototype)机制 prototype是javascript实现与管理继承的一种机制,也是面向对象的设计思想.构造函数的原型存储着引用对象的一个指针,该指针指向与一个原型对 ...

  4. 深入理解 Javascript 面向对象编程(转)

    一:理解构造函数原型(prototype)机制 prototype是javascript实现与管理继承的一种机制,也是面向对象的设计思想.构造函数的原型存储着引用对象的一个指针,该指针指向与一个原型对 ...

  5. 快速理解JavaScript面向对象编程—原型

    总的来说js语言就是门面向对象编程的语言,对象这个概念几乎贯穿了整个js的学习. 对象 创建对象两种方法:(若要生成对象实例必须调用构造函数) 1.var obj = {name:"jer& ...

  6. 悟透JavaScript(理解JS面向对象的好文章)

    引子 编程世界里只存在两种基本元素,一个是数据,一个是代码.编程世界就是在数据和代码千丝万缕的纠缠中呈现出无限的生机和活力. 数据天生就是文静的,总想保持自己固有的本色:而代码却天生活泼,总想改变这个 ...

  7. 03.JavaScript 面向对象精要--理解对象

    JavaScript 面向对象精要--理解对象 尽管JavaScript里有大量内建引用类型,很可能你还是会频繁的创建自己的对象.JavaScript中的对象是动态的. 一.定义属性 当一个属性第1次 ...

  8. 深入理解javascript中实现面向对象编程方法

    介绍Javascript中面向对象编程思想之前,需要对以下几个概念有了解: 1. 浅拷贝和深拷贝:程序在运行过程中使用的变量有在栈上的变量和在堆上的变量,在对象或者变量的赋值操作过程中,大多数情况先是 ...

  9. JavaScript面向对象的理解

    JavaScript面向对象的理解  笔记链接: http://pan.baidu.com/s/1c0hivuS 1:JavaScript 中分两种对象,函数对象和普通对象new Function() ...

随机推荐

  1. Android零基础入门第39节:ListActivity和自定义列表项

    原文:Android零基础入门第39节:ListActivity和自定义列表项 相信通过前两期的学习,以及会开发最简单的一些列表界面了吧,那么本期接着来学习更多方法技巧. 一.使用ListActivi ...

  2. Leaflet(Esri)初识

    加载本地地图 <html> <head> <metacharset=utf-8/> <title>IdentifyingFeatures</tit ...

  3. UWP 使用Windows.Web.Http命名空间下的HttpClient使用post方法,上传图片服务器

    1.从相册里面选取图片 /// <summary> /// 1.1 从相册里面选取图片 /// </summary> /// <param name="send ...

  4. 用CDialog实现的消息框MessageBoxST类

    http://blog.csdn.net/akof1314/article/details/5078563

  5. “真正的工作不是说的天花乱坠”,Torvalds 说, “而是在于细节”(Torvalds 认为成功的项目都是99%的汗水和1%的创新)

    在刚刚结束的加利福尼亚州的开源领袖峰会(2月14日-16日)上,Linus Torvalds 接受了外媒的采访,分享了他如何管理 Linux kernel 的开发以及他对工作的态度. “真正的工作不是 ...

  6. cStor云存储、cProc云处理、cVideo云视频、cTrans云传输,云创个人网盘

    http://www.cstor.cn,微信公众号:cstor_cn.      云创大数据是国际上云计算产品线齐全的企业之一,针对爆炸式增长的大数据需求,研发了自主知识产权的cStor云存储.cPr ...

  7. OSGI资料

    http://osgi.codeplex.com/ http://www.iopenworks.com/

  8. 完美解决iis下JWplayer提示Error loading media: File could not be played错误

    最近开发项目需要使用JWplayer插件播放视频,但是无论换那个版本.换什么样的视频总是提示Error loading media: File could not be played错误,废了好大的劲 ...

  9. DNS查询命令

    dig(domain information groper)是一个在类Unix命令行模式下查询DNS,包括NS记录,A记录,MX记录等相关信息的工具 一.简单介绍使用dig命令查询DNS的方法 dig ...

  10. vue-cli3.x npm create projectName 报错: Unexpected end of JSON input while parsing near......

    npm 版本与node版本还有webpack版本之间的问题 清理缓存,“ npm cache clean --force " 一切OK