JavaScript是面向对象的。与传统的基于类(class-based)的面向对象语言,例如Java和C++等不一样,JavaScript属于基于原型链(prototype)的面向对象语言。
1. 什么是对象
对象是类的一个实例。
类(class)可以看成一种群体的抽象。比如小明和小红都属于人类,那么人类就是一个class,而小明是人类这个class的一个实例。
对于编程语言来说,类是一种数据类型抽象(data type definition),它包含了数据(data member)和方法(function member)两部分。
(这句话结合下面的例子重点理解一下)
class Person {
// 数据
constructor(name, age) {
this.name = name;
this.age = age;
}
// 方法
eat() {
// 吃东西
}
sleep() {
// 睡觉
}
}
回到对象身上。对象是类的一个实例,小明是一个对象,他是人类的一个实例。
2. JS生成对象
JS在ES6之后才引入了class的概念,而之前是通过构造函数和原型链生成对象的。
// 构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
// 原型链
Person.propotype.eat = function() {
// eat方法
}
可以理解为类(class)中的 数据对应JS中的构造函数,方法对应JS中的原型链方法。
JS通过构造函数生成对象实例:var xiaoming = new Person(‘xiaoming’, 20);
3. 什么是面向对象
面向对象实际上就是以对象为核心。
面向对象语言是一类以对象作为基本程序结构单位的程序设计语言,指用于描述的设计是以对象为核心,而对象是程序运行时刻的基本成分。
面向对象编程将数据与功能进行组合,并将其包装在被称作“对象”的东西内。通过对象来实现编程目的,这是我理解的面向对象编程。
面向对象和面向过程的区别:(盗用一个很简单但是很直观的例子)
面向过程:
- 开门(冰箱);
- 装进(冰箱,大象);
- 关门(冰箱)。
面向对象:
- 冰箱.开门()
- 冰箱.装进(大象)
- 冰箱.关门()
在面向过程的做法中,冰箱装大象是通过组织一连串的动作来完成目的的。而面向对象的做法中,我们以对象为核心,调用对象方法来实现目的。
面向对象的三大特征是 封装、继承和多态
4. JS实现面向对象的三要素
4.1 封装
把客观事物封装成抽象的类,隐藏属性和方法的实现细节,仅对外公开接口。
构造函数 + 原型链 本身就是封装。接口就是构造函数本身,通过new的方式封装一个对象数据。
4.2 继承
子类可以使用父类的所有功能,并且对这些功能进行扩展。继承的过程,就是从一般到特殊的过程。
举个例子,人 ——> 程序员,程序员(子类) 继承 人(父类)的所有功能和特征,但是会在这些功能的基础上进行扩展,比如加上 编程 这一项功能。
JS实现继承的方式
(以下代码是js的组合继承,需要理解call/apply 和 原型链)
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.eat = function() {
// 吃饭
}
// 以上是一父类Person的构造函数和原型链
function Programmer(name, age) {
// 继承父类的数据格式
Person.apply(this, arguments);
}
// 继承父类的方法
Programmer.prototype = new Person();
4.3 多态
不同对象对同一消息的不同响应。
多态最根本的作用就是通过把过程化的条件分支语句转化为对象的多态性, 从而消除这些条件分支语句。
盗用一个例子:本人家里养了一只鸡,一只鸭。当主人向他们发出‘叫’的命令时。鸭子会嘎嘎的叫,而鸡会咯咯的叫。转化成代码形式如下
// 非多态代码示例
var makeSound = function(animal) {
if(animal instanceof Duck) {
console.log('嘎嘎嘎');
} else if (animal instanceof Chicken) {
console.log('咯咯咯');
}
}
var Duck = function(){}
var Chiken = function() {};
makeSound(new Chicken());
makeSound(new Duck());
// 多态的代码示例
var makeSound = function(animal) {
animal.sound();
}
var Duck = function(){}
Duck.prototype.sound = function() {
console.log('嘎嘎嘎')
}
var Chiken = function() {};
Chiken.prototype.sound = function() {
console.log('咯咯咯')
}
makeSound(new Chicken());
makeSound(new Duck());
上述例子中,非多态代码中的makeSound中有很多条件语句,需要根据不同的参数作出不同的行为,并且如果有扩展,比如加上猪叫就需要改动这个方法的代码。
而多态代码调用对象自身的方法,一行代码即可实现不同对象对于同一个消息(“发出叫声”这条消息)的不同的响应。
从多态的角度也比较适合理解面向对象。