一. JavaScript面向对象前言
1.1 什么是对象?
Everything is object (万物皆对象)。
对象到底是什么,我们可以从两个层次来理解。
- 对象是单个事物的抽象
一本书、一辆汽车、一个人都可以是对象,一个数据库、一张网页、一个与远程服务器的连接也可以是对象。当实物被抽象成对象,实物之间的关系就变成了对象之间的关系,从而就可以模拟现实情况,针对对象进行编程。
- 对象是一个容器,封装了属性(property)和方法(method)
属性是对象的状态,方法是对象的行为(完成某种任务)。比如,我们可以把动物抽象为animal对象,使用“属性”记录具体是那一种动物,使用“方法”表示动物的某种行为(奔跑、捕猎、休息等等)
在实际开发中,对象是一个抽象的概念,可以将其简单理解为 : 数据集或功能集。
1.2 什么是面向对象?
面向对象只是过程式代码的一种高度封装,目的在于提高代码的开发效率和可维护性
小编的理解:面向对象就是说,使用对象的时候,你可以直接使用它所提供的功能而忽略其内部组成情况。面对对象不一定只有在编程界里才有,我们生活中无处不在;比如说,你家里的电视机,你使用了遥控,就能操作电视机,但是你实际上不知道这台电视机里面是什么零件组成的,你只要知道,我拿到遥控就可以操作电视机就好了。这就是一种面向对象的思想。
1.2.1 什么是面向对象编程?
面向对象编程 —— Object Oriented Programming,简称 OOP ,是一种编程开发思想。
它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。
在面向对象程序开发思想中,每一个对象都是功能中心,具有明确分工,可以完成接受信息、处理数据、发出信息等任务。
因此,面向对象编程具有灵活、代码可复用、高度模块化等特点,容易维护和开发,比起由一系列函数或指令组成的传统的过程式编程(procedural programming),更适合多人合作的大型软件项目。
1.2.2 面向对象与面向过程
- 面向过程就是亲力亲为,事无巨细,面面俱到,步步紧跟,有条不紊
- 面向对象就是找一个对象,指挥得结果
- 面向对象将执行者转变成指挥者
- 面向对象不是面向过程的替代,而是面向过程的封装
二. 对象定义的两种方式
2.1 字面量的方式进行定义
var obj = {
name: "Tom ",
sex: " man",
age:19,
run:function(){
console.log("一天跑一公里");
}
}
2.2 使用 new Object() 进行定义
var obj = new Object();
obj.name = "Tom ";
obj.sex = " man";
obj.age = 19;
obj.run = function(){
console.log("一天跑一公里");
}
三. 类和对象
3.1 什么是类(Class)?
具有相同特性(数据元素)和行为(功能)的对象的抽象就是类。因此,对象的抽象是类,类的具体化就是对象,也可以说类的实例是对象,类实际上就是一种数据类型。类具有属性,它是对象状态的抽象,用数据结构来描述类的属性。类具有操作,它是对象行为的抽象,用操作名和实现该操作的方法来描述。
3.2 类和对象的区别
作为初学者,容易混淆类和对象的概念。类(Class)是一个抽象的概念,对象则是类的具体实例。比如:人是一个类,司马迁,李白,杜甫都是对象;首都是一个类,则北京,伦敦,华盛顿,莫斯科都是对象;动物猫是一个类,则Kitty、Grafield 和 Doraemon 都是对象。
我们可以说 Kitty 猫的体重是 1.5kg,而不能说猫类的体重是 1.5kg;可以说李白是诗人,而不能说人类是诗人。状态是描述具体对象而非描述类的,行为是由具体对象发出的而非类发出的。
3.3 类和对象的关系
类与对象的关系就如模具和铸件的关系,类实例化的结果就是对象,而对象的抽象就是类,类描述了一组有相同特性(属性)和相同行为的对象。
class person{ }//这个是类
$obj = new person();//类的实例化就是对象
四.创建对象的三种方式
4.1 工厂模式,使用简单的函数创建对象,为对象添加属性和方法,然后返回对象
// Class 模板
function Person(name,sex,age){
var obj = {};
obj.name = name;
obj.sex = sex;
obj.age = age;
obj.run = function(){
console.log("每天坚持跑步");
}
return obj;
}
// 实例化
var person1 = Person("Tom","sex",19);
//操作
person1.run(); // 输出结果:每天坚持跑步
4.1.1 工厂模式的优缺点
优点:
1、 在工厂模式中,用户只需要知道所要生产的具体东西,无须关心具体的创建过程,甚至不需要具体产品类的类名。
2、 在系统增加新的产品时,我们只需要添加一个具体产品类和对应的实现工厂,无需对原工厂进行任何修改,很好地符合了“开闭原则”。
缺点:
1、 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
4.2 构造函数模式。
创建自定义引用类型,可以像创建内置对象实例一样使用new操作符,这种方法的缺点是,构造函数的每个成员都无法复用,每次创建出的对象都只有私有变量和私有方法,不能实现共用
//构造函数(这里就创建了一个Class模板)
function Person(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
this.run = function(){
console.log("每天坚持跑步");
}
}
// 实例化 ( new Object())
var person1 = new Person("Tom","man",19);
//操作
person1.run();// 每天坚持跑步
4.2.1 构造函数的改进
// 构造全局的对象
var action = {
run:function(){
console.log("每天坚持跑步");
}
}
//构造函数
function Person(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
this.run = action.run;
}
//实例化
var person1 = new Person("Tom","man",19);
person1.run();
分析: 为什么要改进构造函数?
我们都知道当实例化一个对象后,那么这个对象就拥有了模板的属性和方法,
当我们使用方法时首先会在内存中开辟一份空间,然后在执行相应的操作。假设我们实例化一万个对象,那么这一万个对象在执行方法时都要在内存中开辟空间,这样只会浪费内存的空间,这时如果能用一个操作代替一万个操作那样岂不是美哉,所以小编这里用了一个全局的对象,即使是一万个对象使用这个方法只会在内存中开辟一份空间。
但是这也有缺点,我们都知道全局变量和局部变量,全局变量易造成污染并且声明周期比较长,那么全局对象也是一样的,有没有一种方式可以不用全部对象呢?当然有,见下面的第三种创建模式
4.3 原型模式,使用构造函数的prototype属性来指定共享的属性和方法,即使用构造函数定义实例属性,使用原型定义共享的属性和方法
//构造函数
function Person(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
}
//使用原型对象 Object.prototype
Person.prototype.run = function() {
console.log("每天坚持跑步");
}
//实例化
var person1 = new Person("Tom","man",19);
person1.run();// 每天坚持跑步