开篇废话是一种情怀
在我们开始学习面向对象之前,首先得先想一个问题,那就是何为对象?
- 在日常生活中我们有男朋友\女朋友,称之为对象。有了男朋友可以为你遮风挡雨,有了女朋友可以为你洗衣做饭,同理,在我们的二进制编程世界里,对象完全可以理解为工具或者工具包,当然,在某种特定情况下,我们也可以把人比作是工具。
- 面向对象编程其实是一种思想、思维的转变,从面向过程转变成面呈对象。面向过程注重的是过程,而面向对象注重的是结果,两者的目的相同,但是实现方式却不尽相同。
- 据说,面向对象思维最早是一个生物学家提出来的,他说:"我们编写的代码就好比生物的每一个细胞,我们的身体的每一个组件都代表一个工具,手供我们吃饭,腿供我们行走,不管那天手不能用了,但它不会影响脚的行走,如果能把每一类型的代码抽取成一个一个的工具,好比,钳子、镊子、锤子,那我们对代码、对工具的管理就会显得非常方便,只需要将这一类工具放到一个工具包里面即可。”
- 天了噜,废话不多说了,好像开篇废点话,是一种习惯!下面就让我们开始认识面向对象编程。
- 学习面向对象之前,得先把下面这些东西搞明白!
Js语言的回顾
-
三个组成部分
- BOM:全称Browser Object Model 浏览器对象模型,核心对象(window loacation);
- DOM:Document Object Model 文档对象模型,DOM树,本身为我们操作页面元素提供了一套方法(API),API:application programming interface 应用程序编程接口
- ECMAScript:规定js的核心语法,js语句,关键字,保留字
-
数据类型
- 基本数据类型(简单数据类型)
string 字符串类型
number 数值
boolean 布尔类型(true | false)
undefined 未定义
null 空(对象) 这个类型有点特殊- 复杂数据类型(复合数据类型)
Object 对象类型
Array 数组类型
Funcation 函数类型
Date 日期类型
String 对象
Number
Boolean**判断数据类型的关键字是 typeof **
注意:
复杂数据在使用typeof操作的时候,打印出来的结果都是object ,除了函数等于和全等
赋值(=)
等于符号(==):比较的时候只判断数值是否是相等的
全等符号(===):比较的时候不仅要比较数据还需要比较类型
不等于(!=)
不全等于(!==)关系运算符
返回值:布尔类型,要么是true要么是false
大于 >
小于 <
大于等于 >=
小于等于 <=
- 逻辑运算符(重点)
- 逻辑非( ! ) 取反
- 逻辑或( || )
>**语法:表达式1 || 表达式2
结果:
判断表达式1,如果表达式1为真,那么就返回表达式
如果表达式1的值为假,那么就返回表达式2**
- **逻辑与(&&)**
>**语法:表达式1 && 表达式2
结果:
如果表达式1为真,返回表达式2
如果表达式1为假,返回表达式1**
- **返回值是表达式,而不是布尔值**
- 值类型和引用类型(重点)
- 值类型
>**string
number
boolean
undefined
值类型:存储的是具体的值
赋值:
1.把右边变量存储存储的值(具体的数据)复制一份给左边的变量
2.值类型的赋值,是简单数据的复制,他们保存在相对独立的空间中,彼此不会影响
**
- 引用类型
>**object类型
引用类型:存储的是指向具体值得地址(引用)
赋值:
1.把右边变量存储存储的值(指向具体数据的地址)复制一份给左边的变量
2.引用类型赋值:修改了某个对象的属性,对另外一个对象的属性会有影响
**
- 在函数中的使用
值类型作为函数的参数:
实参和形参他们的数据是相互独立的
<script>
function func(param){
console.log(param); //我是字符串
param = "我也是一个字符串";
console.log(param);
}
var a = "我是字符串";
func(a);
console.log(a);
</script>
引用类型作为函数的参数:
形参和实参共享同一份数据,修改其中的某个对象对另外一个对象也会有影响
<script>
//02 引用类型作为函数的参数传递
var obj = {name:"小明"};
function funcName(param) {
param.name = "小王";
param = {
name:"张明明"
};
console.log(param.name); // 张明明
}
funcName(obj);
console.log(obj.name); // 小王
//
//
var arr1 = [1,2,3];
var arr2 = arr1;
console.log(arr1);
console.log(arr2);
//该行代码切断和arr1的关系,对象内保存的地址指向了另外一块内存空间
arr1.push(4);
arr2 = [1,2,3];
console.log(arr1); //1,2,3,4
console.log(arr2); //1,2,3
</script>
- 对象的动态特性
- 已经定义好的对象,我们对它进行增删改查的操作
- 访问对象有两种形式:
**
1.点语法
在使用点语法设置对象的属性的时候,如果对象中不存在改属性,就是增加操作
如果对象中已经存在该属性,那么就是修改操作
2.[ ] 中括号语法
对象:键 - 值(key-value)对的集合
注意点:在使用[]语法的时候,键应该使用双引用
**
in关键词的使用
作用:
1.遍历对象的key
2.判断某个对象中是否存在指定的属性语法
键 in 对象 返回值:布尔类型的值
注意点:在使用in关键字的时候,key是字符串,需要加上双引号遍历数组
遍历对象 在这里必须使用[ ]语法不能直接使用点语法
在数组中索引是key ,数组的元素是value-
delete关键字
-
作用:
(1) 删除对象中的属性
(2) 删除没有使用var关键字声明的全局变量
注意:
(1)返回值 布尔类型的值(我们可以通过该值来判断是否删除成功)
(2)使用var关键字声明的变量无法被删除
(3)删除对象中不存在的属性没有任何变化,但是返回值为true
(4)不能删除window下面的全局变量(使用var声明),但是可以删除直接定义在window上面的属性
-
作用:
循环对象
for循环
while
do...while(至少会执行一次)
for...in(主要用于遍历对象)
-
函数的几种创建
声明函数
<script>
function 函数名称 (形参1,形参2)
{
//函数体
}
//调用
//函数的名称();
function funcName (){
}
</script>
函数表达式
<script>
//01 匿名函数
var func01 = function (){
};
//02 命名的函数表达式
var func02 = function func(){
};
</script>
使用构造函数创建函数对象
<script>
var func = new Function(); //没有内容(没有函数体)
func();
function funcTest (){}; //等价
var func02 = new Function("console.log('demo');");
func02();
</script>
<script>
var obj = {name:"zhangsan"};
var obj2 = new Object();
var obj3 = {};
</script>
回顾前面这些呢,就是想让接下来看面向对象的时候,脑海中有个印象和回忆,当然,这也是想到会有一些编程小白理解起来困难的原因。知识点有点枯燥,学编程嘛 得有点耐心才行.
面向过程 & 面向对象
- 都是一种解决问题的思路(思想)
- 面向过程在解决问题的时候,关注的是解决问题需要的一个接着一个的过程(步骤)
- 面向对象在解决问题的时候,关注的是解决问题所需要的对象.
- 举例
就用洗衣服来形象的打个比方
如果你是用手洗的话,那就不得不考虑 倒水-搓衣服-加洗衣液-清水涮-手拧干-晾起来 这就是面向过程
但如果你忽略这些步骤 直接放洗衣机洗的话 可能都不用考虑晾干的步骤 这就是面向对象
什么是对象
- 对象的特征 (静态的描述信息),比如:学号 - 性别 - 年龄 - 家庭住址 - 身高 - 体重 ... 等等
- 有的对象有行为 (动态的特征), 比如:吃饭 - 睡觉 - 开车 - 玩游戏 - 谈恋爱
- 代码示例
var zhangsan = {
name:"张三",
sex:"男",
age:18,
address:"天上人间1号公馆",
eat:function () {
console.log('能吃');
},
sleep:function () {
console.log("能睡");
},
say:function () {
console.log("能说话");
},
run:function () {
console.log("能运动");
},
song:function () {
console.log("能唱歌");
}
};
//打印对象的属性并调用相关的方法
console.log(zhangsan.name,zhangsan.age,zhangsan.address);
zhangsan.say();
zhangsan.sleep();
现实中的对象和编码中的对象
- 静态的描述信息:属性
- 动态的行为特征:方法
- 面向对象和面向过程都是解决问题的一种方式(思想),没有孰优孰劣之分
- 面向对象本身是对面向过程的封装
为什么要使用面向对象编程?
- 更方便
- 复用性会更好
高内聚和低耦合(电路)
冗余(重复的东西)-->封装(提取相同的部分作为函数体,抽取不同的部分作为参数)
js对象是由两个对象组成的
- 一个叫构造函数对象
- 一个叫原型对象
编程语言
- ** 汇编语言是对内存的地址进行编程的**
- ** C语言是第一款比较流行的面向过程语言 **
- ** C语言和面向对象是编程世界一个划时代的里程碑**
- ** 构造函数和普通函数是一回事,只不过构造函数是通过普通函数实现的**
面向对象的特性:
- 封装
作用:方便代码的维护,提高代码的复用性,更安全的访问数据的方式
注意: js中的封装多了一层意思,就是使用对象来封装变量和函数 - 继承
- 现实生活中的继承:继承遗产,一个人获得另一个人所拥有的财富或者是资源的方式。
- 编程语言中的继承:一个类(对象)获得另外一个类(对象)的属性和方法的一种方式。
- 面向对象的语言特征:类(C++)C(没有类)
- js中没有类(class),支持面向对象的语言。
- 多态
- 表现:
对于相同的操作,不同的对象表现出不同的行为。
隐藏不同。 - 实现:
js天生具备多态的特性(弱类型的语言)
- 表现:
创建对象的四种方法
- 字面量的方式
var book1 = {
name:"悟空传",
author:"今何在",
press:"湖南文艺出版社",
price:"28.00",
logDes:function(){
console.log("书名:" + this.name + "作者:" + this.author);
}
}
var book2 = {
name:"什么是批判",
author:"福柯",
press:"北京大学出版社",
price:"52.00",
logDes:function(){
console.log("书名:" + this.name + "作者:" + this.author);
}
}
var book3 = {
name:"数据结构",
author:"严蔚敏",
press:"清华大学出版社",
price:"30.00",
logDes:function(){
console.log("书名:" + this.name + "作者:" + this.author);
}
}
console.log(book1.name);
boo1.logDes();
存在的问题:
创建的对象无法复用,复用性差
如果需要创建多个相似的对象,那么代码中冗余度太高(重复的代码太多)
- 内置的构造函数
//01 创建空的对象
var book1 = new Object();
//02 设置属性
book1.name = "花田半亩";
book1.author = "田维";
book1.price = "40.01";
//03 设置方法
book1.logDes = function (){
console.log("书名:" + this.name);
}
book1.logDes();
//创建多个对象
var book2 = new Object();
book2.name = "三国演义";
book2.author = "罗贯中";
book2.price = "34.01";
book2.logDes = function (){
console.log("书名:" + this.name);
}
console.log(book1);
console.log(book2);
存在的问题:
创建的对象无法复用,复用性差
如果需要创建多个相似的对象,那么代码中冗余度太高(重复的代码太多)
- 简单工厂函数创建对象
//01 封装创建对象的过程
function createBook () {
var book = new Object();
book.name = "声名狼藉者的生活";
book.price = 42.00;
book.author = "福柯";
book.press = "北京大学出版社";
book.read = function () {
console.log("我的书名为:声名狼藉者的的生活,作者为福柯....");
};
return book;
}
//02 使用封装好的工厂函数来创建对象
var book1 = createBook();
var book2 = createBook();
//03 打印对象的属性并调用对象的方法
console.log(book1.name);
console.log(book2.name);
book1.read();
book2.read();
console.log("_________________________");
//04 说明:以上代码确实能够快速简单的创建出新的对象,但是创建出来的对象内部的属性和方法相同,这并不是我们想要的。
//05 对上面的工厂函数进行改进
//改进思路:封装不变的部分,提取变化的部分作为参数
function createBookNew (name,price,author,press) {
var book = new Object();
book.name = name;
book.price = price;
book.author = author;
book.press = press;
book.read = function () {
console.log("我的书名为:"+book.name+",作者为"+book.author+"....");
};
return book;
}
//06 使用新的工厂函数来创建对象
var book1 = createBookNew("声名狼藉者的的生活","42.00","福柯","北京大学出版社");
var book2 = createBookNew("人性的枷锁","49.00","毛姆","华东师范大学出版社");
var book3 = createBookNew("悟空传","28.00","今何在","湖南文艺出版社");
//07 打印对象的属性,调用对象的方法
console.log(book1.name);
console.log(book2.name);
console.log(book3.name);
book1.read();
book2.read();
book3.read();
存在的问题:
如果创建多个不同类型的对象,那么我们无法分辨
-
自定义构造函数创建对象
- 提供一个构造函数
- 通过this指针来设置属性和方法
- 通过new操作符创建对象
//1.提供一个构造函数
//构造函数简单介绍:
//作用:对对象进行一些初始化的设置
//和普通函数区别:(01)首字母大写(02)调用方式不一样和new配合使用
function Person(name,age){
// 默认 创建对象
//var o = new Object();
//默认会赋值给this
//this = o;
//2. 通过this指针来设置属性和方法
this.name = name;
this.age = age;
this.showName = function(){
console.log(this.name);
};
this.showAge = function(){
console.log(this.age);
}
//默认返回
//return this;
}
//3. 使用new操作符来创建对象
var p1 = new Person("张三",20);
var p2 = new Person("张老汉",200);
console.log(p1);
console.log(p2);
/*
1. 自定义构造函数方式创建对象内部的实现细节
1.1 我们在使用new关键字调用构造哈函数的时候,内部默认会创建一个空的对象
1.2 默认会把这个空的对象赋值给this
1.3 通过this来设置新对象的属性和方法
1.4 在构造函数的最后,默认会把新创建的对象返回
2.自定义构造函数和工厂函数对比
2.1 函数的名称不一样,构造函数首字母大写
2.2 自定义构造函数创建方式内部会自动的创建空对象并且赋值给this
2.3 默认会自动返回新创建的对象
3.返回值
3.1. 没有显示的return ,默认会把新创建的对象返回
3.2. 显示的执行了return语句,就得看具体的情况
3.2.1 返回的是值类型,那么直接忽略该返回,把新创建的对象返回
3.2.2 返回的是引用类型的数据,会覆盖掉新创建的对象,直接返回引用数据类型的值
*/
function Dog(name)
{
this.name = name;
//return "demo"; 忽略
//return function (){};
}
var dog = new Dog("阿黄");
console.log(dog);
构造函数的的注意事项
- 函数传值
function Student(number,className,log){
this.number = number;
this.className = className;
this.log = log;
}
var stu1 = new Student("201601","九阴真经修炼01班",function(){
console.log("学号:" + this.number);
});
var stu2 = new Student("201602","九阴真经修炼01班",function(){
console.log("班级名称:" + this.className);
});
stu1.log();
stu2.log();
- 对象的类型(判断)
function Person(){};
function Dog(){};
var p1 = new Person();
var dog1 = new Dog();
//关键字 instanceOf 用来判断当前对象是否是某个类型的实例(检查某个对象是否是使用指定构造函数创建的)
//语法: 对象 instanceOf 构造函数(类型)
console.log(p1 instanceof Person);
console.log(p1 instanceof Dog);
console.log(dog1 instanceof Person);
console.log(dog1 instanceof Dog);
- 构造器属性(获取
function Person(){};
function Dog(){};
var p1 = new Person();
var dog1 = new Dog();
//在所有的对象中,都拥有一个构造器属性:constructor
console.log(p1.constructor);
console.log(dog1.constructor);
-
函数调用
new :创建对象,并在最后返回该对象
构造函数:用于初始化对象
以普通函数的方式来调用构造函数,那么内部的this指向的是window
function Person(name)
{
if(this instanceof Person)
{
this.name = name;
}else
{
return new Person(name);
}
}
var p1 = new Person("哔哩哔哩");
//构造函数本身是一个函数,在调用可以直接调用
var p2 = Person("哗啦哗啦"); //这是一个错误的演示(不要这样写代码)
console.log(p2); //undefined
-
存在问题
** 把函数写在外部,破坏了封装性。
增加一个全局变量。**
var showName = function(){
console.log("姓名:");
}
function Person(name,age){
this.name = name;
this.age = age;
this.showName = showName;
}
//创建对象
var p1 = new Person("张小花",18);
var p2 = new Person("张全蛋",99);
p1.showName();
p2.showName();
//每创建一个对象,内部都会声明一个showName函数
console.log(p1.showName == p2.showName); //false