目 录CONTENT

文章目录

面向对象程序设计(入门篇)

Administrator
2020-07-24 / 0 评论 / 3 点赞 / 12230 阅读 / 15087 字

面向对象程序设计(入门篇)

在程序员的眼中,万事万物皆对象,我们那些能够看得见,摸得着,感受得到,想象得出来的这些东西都可以理解为对象。如看得见的人,摸得着的物体,感受到的温度,想得得聘的一些物体,它们都是对象

如何给女朋友解释什么是面向对象编程?

周末午后,我正在愉快的打着游戏。女朋友拿着一本《面向对象编程》过来找我。

什么是面向对象?是要面向我写代码吗?

9f510fb30f2442a7aa6ef0da003cc14fd01302f4

不是啦,这个面向对象的对象不是你这个对象啦。

此时,我突然感受到了一股莫名的杀气。

什么?你还有其他对象吗?有我好看吗?

b21bb051f8198618145f77989b9242778bd4e612

什么是面向对象?

面向对象,英文名字叫Object Oriented,是一种软件开发方法。是和面向过程相对应的。

别给我拽英文。给我详细说说,说不明白今天就没完。

我有点饿了,要不然你给我做点饭,我慢慢的详细给你讲吧。

我现在就想听你给我讲,咱们直接点外卖吧,别自己动手做饭了。

aa18972bd40735faa11826b34c2e63b70e240857

其实,对于吃饭这件事儿,就可以分为面向过程吃饭和面向对象吃饭自己亲自下厨就是面向过程点外卖就是面向对象

在面向过程的吃饭中,我们想要填饱肚子,需要自己亲自下厨把这顿饭做出来,那么,我们就需要先想好吃什么、然后去买菜、洗菜、洗米、蒸饭、炒菜等等一系列的事情。

function 做饭(){制定菜单;买菜;洗菜;洗米;蒸饭;炒菜;reutrn 饭菜}那么,你说和点外卖相比,自己做饭有哪些缺点啊?

那还用说,麻烦呗。

b21bb051f8198618145f77989b9242778bd4e612-1588213618474-1656299238923

的确,面向过程编程也一样,由于想要完成做饭这件事,需要自己定义很多个方法。除此之外,还有很多遇到很多其他问题,比如:

我不想吃米饭,我想吃馒头。

上次买的菜家里面还有,不需要去买菜。

中午吃剩下的菜家里面还有,直接热一热就可以吃了。

这次去的一家超市提供洗菜服务,不需要我们自己洗菜了。

以上这些突发事件,在编程中就叫做需求变更或者新的需求,这种事情发生是必然会发生的。

那么,有新的需求了怎么办,上面这种自己动手做饭的场景,就只能重新拼凑咯。

对于程序员来说,就需要通读代码,找出可以复用的方法,然后重新调用,不能复用的就重新写一个。时间久了,方法就会越来越多,系统维护越来越复杂。


面向对象,其实就是我们通过点外卖的方式来“做饭”。我们知道我们需要一顿饭,我们只需要打开外卖软件,在里面选择我们需要的菜品然后下单就可以了。我们不关心饭店做饭的过程。想吃什么点什么,家里来人了就再下一个订单,不想吃米饭了,想吃馒头了,也可以给饭店打电话,让他们把米饭换成馒头。【我们不关注你的实现过程,我只根据我的要求关注结果】

外卖软件.点餐(红烧肉,糖醋鱼,可乐一瓶).送达时间(一小时后).备注(可乐加冰)所以,通过面向对象的方式“做饭”,就像上面的代码一样。

哦,我明白了,面向对象就是把本来可能需要自己做的事情交给别人来做?对于我来说,外卖软件就是个对象,我再面向他“做饭”,其实是他帮我做的。

8c1001e93901213f613c1cc185985ad52f2e9520

额、你说的也对,也不对。在这个场景中,确实可以把外卖软件当做是「对象」。其实,在面向对象编程中,抛弃了函数,想要实现一个功能不再是通过函数的叠加调用实现的了。而是通过对象。

对象就是对事物的一种抽象描述。现实世界中的事物,都可以用「数据」和「能力」来描述。【其实也就是万事万物皆对象】

比如我要描述一个人,「数据」就是他的年龄、性别、身高体重,「能力」就是他能做什么工作,承担什么样的责任。

描述一个外卖软件,「数据」就是他包含的菜品,而「能力」就是他可以点菜。


上面是通过语义的角度来理解什么是面向对象

如果它是一个对象,那么它应该具备 以下几个特点

  1. 对象具备属性

    属性就是用于描述当前对象的特征的,可以理解为上在面的【数】

  2. 对象具备方法

    方法就是一个对象的能力,例如它可以做什么事情。可以理解为上面的【能力】

  3. 对象应该是可以继承的

    父级对象里面的某些方法或属性或以在子级对象里面,继续使用

? 想一想:为什么需要对象这个概念,如果没有对象应该怎么办,会有什么问题?

场景 : 现在我希望将我们班的杨兰芳同学和赵聪同学的信息记录下来,怎么办呢?分别记录它们的姓名,性别,年龄和爱好

var name1 = "杨兰芳";
var sex1 = "女";
var age1 = 18;
var hobby1 = "看书";
//以上的四个变量就都属于杨兰芳的
var name2 = "赵聪";
var sex2 = "男";
var age2 = 19;
var hobby2 ="逛街";
//以上的四个变量就属于 赵聪的

通过上面的代码,我们就看到,如果我们要将班上所有学生的信息全部记录下来,这个时候就很为难,我们需要定义很多个变量

上面我们是每四个变量才能够描述一个学生的信息,但是如果我们每次都定义变量,这样就会显得很麻烦,在程序员的眼中,我们段代码都应该要做一个特点叫**“高内聚,低耦合”**

高内聚可以理解为“物以类聚”,某些东西或者事务具备相同的属性的时候,我们就应该把它归纳为一类

如果没有对象,上面的东西就很难实现了,所以我们迫切的需要一种集中形式的数据管理方式,而这种管理方式就是面向对象编程

对象的创建

对象的创建可以理解为对象的封装

通过键值对创建

在JavaScript的对象里面,键(key)也叫对象的属性名,值(value)也叫对象的属性值。所以键值对的创建其实就是属性名与属性值的方式来创建对象

var 对象名 = {
   属性名1:属性值1,
   属性名2:属性值2
   //.......
};

我们现在已经知道了键值对的创建语法格式,那么我们就将刚刚的学生信息的创建过程使用对象的形式来表述一下

var stu1 = {
    name: "杨兰芳",
    sex: "女",
    age: 18,
    hobby: "看书"
};
var stu2 = {
    name: "赵聪",
    sex: "男",
    age: 19,
    hobby: "逛街"
};

在上面的代码里面,我们只定义了两个变量分别是是 stu1stu2,但是它们都是对象,我们分别这两个对象下面给它添加了四个属性分别是name,sex,age,hobby,这四个属性都是用于描述stu1stu2这两个对象的特征的

属性只是对象的第一个特点,还有可以有方法(以就是我们以前的函数,在讲面向对象之前,我们把函数叫函数,但是讲到面向对象以后,我们的函数就应该叫方法了)。怎么样在对象里在去创建方法呢?

var stu1 = {
    name: "杨兰芳",
    sex: "女",
    age: 18,
    hobby: "看书",
    sayHello: function(){
        console.log("大家好,我是对象里面的方法");
    }
};

?如果我们希望在方法里面拿到当前对象属性,应该怎么办呢?

第一种方式

var stu1 = {
    name: "杨兰芳",
    sayHello: function(){
        console.log("大家好,我的姓名是"+stu1.name);
    }
};

但是这种方式有个缺点,它必须要借助于对象名stu1,如果这个时候的stu1的对象名变了,那么方法里面的名子也要变

针对于像上面这个问题,JavaScript有一个特殊的指针变量叫this,在方法的内部,它指向了当前的对象

第二种方法

 var stu3 = {
     name:"赵聪",
     sayHello:function(){
         console.log("大家好,我的姓名是"+this.name);
     }
 }

关于this的用法,后面的专门的章节去讲解

通过Object去创建对象

除了通过上面的{}的键值对方式来创建对象,我们还可以使用Object这个来创建对象

var obj = new Object();		//它得到的就是一个花括号

上面的方式只要与我们之前所学习的数组进行结合,这样就很好理解了

new Array();//得到的是[]			得到的是空的数组
new Object();//得到的就是{}		   得到的是空的对象

得到这个空的对象以后,怎么样向这个对象里面添加属性以及方法呢

var stu1={
  	name:"标哥哥",
    sex:"男",
    age:18,
    sayHello:function(){
        console.log("大家好,我叫"+this.name);
    }
};

上在的写法如果换成Object如下

var stu2 = new Object();            //创建了空的对象
//在当前的对象上面去添加属性和方法
stu2.name = "赵聪";
stu2.sex = "男";
stu2.age = 18;
stu2.sayHello = function(){
    console.log("大家好,我叫" + this.name);
}

上面的两种方式都可以创建对象,但是我们仍然发现一个问题,这两种试如果要去创建多个类型相同的对象则很麻烦,如班上有100个学生,我要把这100个学生的姓名,性别,年龄,爱好,以及sayHello的方法都创建好,这样就很麻烦。通过上面的方式去创建,我要把所有的属性都写100遍,这样就很麻烦

使用构造函数创建对象

本章节是重点,重点中的重点,重要的事情说三遍

首先要弄清楚这个章节就必须要弄清楚另一个事情就是什么是构造函数

函数我们之前都学过,它是通过function来定义的,同时我们也学过函数的几种调用方式

image-20200506152811138

所谓的构造函数其实就是把方法通过new去调用了。通过new调用的方法就叫构造方法,也叫构造函数

//定义了一个普通的方法
function sayHello() {
     console.log("大家好,我是标哥哥");
     return 123;
}
//通过常规的方式去调用
var a = sayHello();			//返回123
//通过构造函数去调用
var b = new sayHello();		//返回一个对象

通过上面的代码我们就可以得到,只要new一个函数(function)就可以得到一个对象

语法格式

var 对象名 = new 函数();

在之前的学习里面,我们其实已经接触了两个构造函数了,分别是ArrayObject它是JavaScript系统置的两个原生构造函数

var arr = new Array();		//执行了Array这个构造函数,返回一个空的数组对象
var obj1 = new Object();	//执行了Object这个构造函数,返回了一个空对象

如果我们想实现自己的构造函数又应该怎么办呢?如果要搞清楚之个,就必须先要理清楚,构造函数与普通函数的区别

通过分析构造函数与普通函数的特点以后,我们就对构造函数有了一个初步的了解

//这也是一个方法,这个方法有三个参数
function Student(_name, _sex, _age) {
    this.name = _name;
    this.sex = _sex;
    this.age = _age;
    this.sayHello = function () {
        console.log("大家好,我叫" + this.name);
    }
}
var stu0 = new Student("杨标", 18, "男");		//执行构造函数Student,传递参数,返回对象

var stu1 = new Student("杨兰芳", "女", 19);

无参数的构造函数

//在这里就定义了一个方法
function abc(){
    console.log("hello world");
}
//这个方法现在是没有形参的,所以我们在调用的时候是不需传递参数的
abc();          //普通函数方式的调用
new abc();      //构造函数调用
//如果这个构造函数没有参数,我们可以把这个小括号给省略掉
new abc;		

使用工厂模式创建对象

上面一个章节我们已经学过了使用构造函数可以快速的去创建相同的对象,但是在以前的时候,我还可以使用工厂模式去创建

提起工厂,我们的脑海里面应该就有画面了。工厂可以批量的创建相同的东西,它与我们刚刚所学的构造函数很相相似,都可以快速的创建相同构造的对象

例如我们现在需要创建学生的信息对象,这个时候怎么办呢?

//这个方法就相当于工厂,专门用于创建学生
function createStudent(_name, _sex, _age) {
    //使用键值对创建对象
    var obj = {
        name: _name,
        sex: _sex,
        age: _age
    };

    //返回刚刚创建的对象
    return obj;
}

var stu1 = createStudent("赵聪", "男", 18);
var stu2 = createStudent("库威", "男", 19);
var stu3 = createStudent("杨兰芳", "女", 20);

通过上面的方式,也可以快速的去创建学生对象。这一种方式其实就是模拟了构造函数的new的过程

构造函数与普通函数的区别

构造函数与普通函数在书写上面没有什么区别,关键点就在于它们的调用方式

  1. 构造函数使用new来调用,普通函数就是函数名+()来进行调用

  2. 构造函数返回值一定是一个对象(也就是当前对象),而普通方法的返回值是根据return关键字来决定的

  3. 普通方法的this指向的是windows也就是浏览器窗体,而构造函数里面的this指向的是创建的的这个对象(也就是当前对象)

  4. 如果是通过new以构造函数执行,在执行的时候可以不加小括号

构造函数使用是以大定字母开头的,所以上面的对象Student它的首字母就是大写的,这是一个代码规范

使用new关键字调用构造函数实际上是经历了4个过程

image-20200506161317530

image-20200506160742770

工厂模式与构造函数模式区别

刚刚我们已经学习了工厂模式创建对象,也学习了构造函数模式创建对象。这两者有什么区别呢?

首先我们先从下面的案例代码来说明一下

//创建学生的工厂
function createStudent(_name, _sex, _age, _sid) {
    // 创建对象
    var obj = {
        name: _name,
        sex: _sex,
        age: _age,
        sid: _sid //学生的编号 
    };
    //返回对象
    return obj;
}

//创建老师的工厂
function createTeacher(_name, _sex, _age, _tid) {
    // 创建对象
    var obj = {
        name: _name,
        sex: _sex,
        age: _age,
        tid: _tid //老师编号
    };
    //返回对象
    return obj;
}
//学生的对象
var stu1 = createStudent("赵聪", "男", 18, "s001");
// 老师的对象
var teacher1 = createTeacher("杨标", "男", 19, "t008");

//创建完上面的两个对象以后,我们分别使用对象的检测关键字instanceof去检测一下
stu1 instanceof Object ;			//true
teacher1 instanceof Object;			//true

stu1与teacher1是两个不同的工厂创建的,但是我们现在根据就没有办法去区别他们的类型,因为它们的内部都是使用{}来创建的,所以它们的本质是一样的。这种缺点对我们后期对象类型的判断有很大的麻烦

正是因为有一个像这样的缺点,我们后期才不会使用工厂模式来创建对象,转面使用构造函数模式去创建对象

使用构造函数去完成上在的对象创建

//学生的构造函数
function Student(_name, _sex, _age, _sid) {
    this.name = _name;
    this.sex = _sex;
    this.age = _age;
    this.sid = _sid;
}

//老师的构造函数
function Teacher(_name, _sex, _age, _tid) {
    this.name = _name;
    this.sex = _sex;
    this.age = _age;
    this.tid = _tid;
}

var stu1 = new Student("杨兰芳", "女", 18, "s002");
var teacher1 = new Teacher("杨标", "男", 19, "t008");


stu1 instanceof Student;        //true
teacher1 instanceof Teacher;    //true

stu1 instanceof Teacher;        //false
teacher1 instanceof Student;    //false

通过构造函数创建的对象,我们就可以检测出这个对象的原型是什么??

对象属性的调用

通过上一个章节的学习,我们可以看到能够在对象里面进行一个方法与必性的创建,但是这个对象创建完成以后,我们怎么样去调用这里面的属性和方法呢

var stu1 = {
    name: "杨兰芳",
    sex: "女",
    age: 18,
    hobby: "看书",
    sayHello: function(){
        console.log("大家好,我是对象里面的方法");
    }
};
//例如,我们怎么样得到姓名,怎么样去调用sayHello的方法呢

第一种调用方法

最常规的调用方式是通过对象.属性名来调用的。如下所示

stu1.name;			//杨兰芳
stu1.age;			//18
stu1.sayHello();	//调用了sayHello这个方法

这种调用方法是最常见的调用方法,但是它仍然有一个小问题,有部分属性它是调用不了的

var stu2 = {
    name:"标哥哥",
    1:"这是另一个属性",
    "a-b":"嘿,我在这里"
}

在上面的代码里面, 我们使用了数字来做属性名,碰到这样的情况的时候,我们上面的这种调用方式就不行了

在这里,我们可以正常的通过stu2.name来调用,但是不能通过stu2.1来调用,这是错的,也不能通过stu2.a-b来调用

image-20200430111420740

所以对于这些特殊的属性,我们需要使用一种特殊的方式来调用

第二种调用方式

var stu1 = {
    name: "杨兰芳",
    age: 18,
    1:"这是另一个属性",
    "a-b":"嘿,我在这里",
    sayHello: function(){
        console.log("大家好,我是对象里面的方法");
    }
};
console.log(stu1.name);     //常规调用
console.log(stu1["name"]);  //第二种调用方式

//接下来看特殊属性名的调用
console.log(stu1[1]);
console.log(stu1["a-b"]);

stu1.sayHello();            //常规调用
stu1["sayHello"]();         //中括号调用

中括号的这种调用方式使用面更广一些,它可以调用常规的属性,还可以调用特殊的属性

本章基础总结

在本章节里面,重要的点如下

  1. 理解面向对象以及对象的概念
  2. 对象的创建的几处方式
  3. 构造函数以及构造函数的特点
  4. 对象属性的调用
3

评论区