前言
JavaScript是一门面向对象的解释型脚本语言,通过利用面向对象的这种特性,实现了代码重用,并构建起了可伸缩的代码框架。作为JavaScript的初学者,因为面向对象是JavaScript的核心部分,所以在开始就略微的去学习了JavaScript的面向对象的基础概念部分,能够对于JavaScript的面向对象积累一些初始概念,并将自己对这些的感悟分享出来与大家交流。
作为初学者,可能有些地方理解不够正确,希望大家能提出自己的见解,欢迎批评指正。
面向对象程序设计最常用到的概念
面向对象程序设计最常用到的概念如下:
- 对象、方法、属性;
- 类;
- 封装;
- 聚合;
- 重用与继承;
- 多态。
1.对象
JavaScript是面向对象的解释型脚本语言,所以面向对象是该编程语言的核心所在。那么什么是对象?对象我们有时候也叫“实例”,实际上就是指事物在程序语言中的表现形式,这类事物可以是人也可以是物,可以是客观存在的具体化对象,也可以是抽象的概念对象。这类事物往往具有其特定的称呼和特征,以及行为等。
例如:有一只黑色的猫在床上睡觉。其中,猫代表的是对象,黑色是颜色,代表属性,睡觉是一种动作行为,代表方法,在床上是睡觉的限定条件,限定动作的条件,也可以看做是传递给睡觉这个方法的参数。
2.类
我们知道在现实生活中,相似对象之间往往具有一些共同的组成特征。比如阿拉斯加犬和哈士奇都属于狗类并具有狗类的特征,因此它们属于同一个类。所以类实际上就是一群具有相同特征的对象并同属一个类组成的集合。阿拉斯加犬是一个实例化对象,哈士奇是一个实例化对象,它们都是由同一个类创造出来的,而这个类还可以创造出其它具有相同特征的实例化对象,所以类也可以当做是一种模板,对象就是在模板上创建出来的实体。
当然,JavaScript并不存在类这一说法,它的一切都是基于对象,依靠着一套原型系统。在传统的面向对象语言中我们可以这样描述:我基于Cat类创建了一个叫做BlackCat的对象,而在基于原型的面向对象的语言中则是这样说道:我将现有的Cat对象扩展成一个叫做BlackCat的对象。
3.封装
封装是用来封装对象中的内容,因此封装实际上就是去阐述对象中包含的内容。这些内容可以是属性,也可以是方法。
例如:一部手机是一个对象,手机里的处理器、电池、电路板等部件就是属性,我们作为用户通常通过手机的按钮、显示屏一类的接口去使用对应的方法,这等价于OOP(面向对象的程序设计)中的调用方法。但是这些接口的实现过程和手机所具有的属性等都是不可见的,我们并不清楚它们内部是如何工作的,只需要通过接口去使用功能即可。在编译类型的语言中我们也是直接去调用方法实现相应的功能即可,而不是去关心它的实现过程。
能够达到以上事例中的内容的封闭性就是封装。而封装的意义就是方便用户操作,优化用户体验。
在某些编程语言中我们可以使用public、private、project、default这些关键字来限定方法和属性的可见性,通过限定分类定义了用户所能访问的层次。但是在JavaScript中,所有的方法和属性都是public,话是这样说,其实JavaScript中也是提供了一些隐藏数据的方法来保护程序的隐私性。
4.聚合
聚合也被称为组合,就是将几个现有对象合并为一个新对象的过程。这个过程实际上是一种思想,在实际解决问题的过程中我们可以采用这种思想将一个问题分解成多个小的问题,这些多个小的问题相对而言更加容易思考,提高解决问题的效率。
例如:在图书管理系统中我们要找《JavaScript高级程序设计》这本书,假若我们不使用检索功能去直接搜寻书,从一个系统包含的成千上万本书中去查找一本书也是一个很费劲的工作。因此我们可以将图书管理系统的功能模块细化,分门别类并有选择有目的的去寻找。《JavaScript高级程序设计》是一本关于前端的书籍,而前端书籍是属于技术类书籍,前端技术类书籍是包含在IT互联网类型中,而IT互联网类型可以在整个管理系统的图书分类中找到,而图书分类这个模块是在进入图书管理系统后比较显眼的功能分类中可以找到。通过将寻找这本书的流程分化成一个个的具体模块的过程再去逐一解决这个问题就是聚合。
注意:以上事例要想实现是需要图书管理系统对于图书的分类比较明确而不是单单的将一堆图书直接聚集在一起,所以可以看出并不是在所有复杂情况下都可以使用聚合去解决问题,但是使用聚合可以解决大多数问题。
如果以上的示例还是令人感到迷惑的话我们再举一个例子。
例如:一个Web开发团队由许多人员组成,这是一个比较复杂的集体,我们如何才能清晰的知道这个集体中包含哪些人,每个人在做什么工作呢?我们需要将这个团队中包含的岗位罗列出来并将我们的对象,也就是开发人员和产品经理一一对应在相应的岗位,其中每一个开发人员或产品经理只是这个Web开发团队对象的一部分,这样划分下来我们就可以解决了这些问题。
总的来说聚合在开发过程中的作用是将分开编辑的代码聚合在一起方便调用。
5.继承
继承是实际开发过程一种比较便捷的方式,通过继承这种方式可以实现代码的重复利用。
例如:人这个对象的名称我们可以将其命名为Person,这个对象中应该包含姓名、年龄、出生日期等属性以及走路、跑步、谈话、吃饭、睡觉等方法。这时候我们想要编写一个Student对象,这个对象拥有和Person对象一样的特征,因此我们可以直接继承Person对象,这样我们只需要通过去重用Person对象去编写Student对象的实现代码部分即可。接着我们还想编写一个Teacher对象依然可以这样做。
通过以上示例就可以实现了代码的复用避免了不停地重写相同的方法和属性,做到高效利用。
在传统的面向对象的程序设计中,继承通常都是指类与类之间的关系,但是JavaScript中并不存在类这样的说法,所以它的继承是发生在对象与对象之间。
当一个对象继承另一个对象的时候,可能会继承的基础上在里面加入新的方法,这个过程被称为“继承对象扩展自被继承对象”或者“继承对象继承自被继承对象”。比如A对象继承B对象,那么就是“A扩展自B”或“A继承自B”。此外我们也可以重新定义被继承的对象中的方法,被重新定义后的方法只是改变了当前继承在该对象中的方法,并不会真正改变被继承对象中的方法,而这种重新定义继承过来的方法的过程叫做方法的覆写。
6.多态
还是上面的例子,Student对象继承了Person对象中所有的方法,Teacher对象也继承了Person对象中所有的方法,拿方法中的跑步举例,跑步是“run”方法,这时候代码中有一个叫做Jack的变量,我们并不知道Jack是属于Person对象还是属于Student对象还是属于Teachar,在这种情况下我们还是可以去调用对象的“run”方法,实现跑步这一方法,形如这种通过相同的方法调用来实现各自行为的能力的就是多态。如果再通俗来讲,就是同一个操作作用在不同的对象上产生不同的解释或者是不同的结果就是多态。
举个栗子:
function Person() {}
Person.prototype.age = function(age) {
return age;
}
function Student() {}
Object.setPrototypeOf(Student.prototype,Person.prototype);
function Teacher() {}
Object.setPrototypeOf(Teacher.prototype,Person.prototype);
var stu = new Student();
console.log(stu.age(18));
var tea = new Teacher();
console.log(tea.age(28));
即使后面再加上一个Master对象,依然可以继续调用,不影响其它代码的调用实现
function Person() {}
Person.prototype.age = function(age) {
return age;
}
function Student() {}
Object.setPrototypeOf(Student.prototype,Person.prototype);
function Teacher() {}
Object.setPrototypeOf(Teacher.prototype,Person.prototype);
function Master() {}
Object.setPrototypeOf(Master.prototype,Person.prototype);
let stu = new Student();
console.log(stu.age(18));
let tea = new Teacher();
console.log(tea.age(28));
let mas = new Master();
console.log(mas.age(38));