24面向对象
# 面向对象
[info] 面向对象(oop)
是一种软件开发方法,一种编程范式。面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。
# 一、面向对象的优势和特性
//优势
1、方便
2、复用性高
3、高内聚低耦合
4、代码冗余低
//特点
1、封装。也就是把客观事物封装成抽象的类。
2、继承。它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
3、多态。允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。
2
3
4
5
6
7
8
9
10
[!NOTE]
%accordion% 历史解说🚀 %accordion%
c 面向过程 过程,难以理解
c++ 面向对象 对象,容易理解,维护性高
ecma es6 (2015)
JavaScript:
js 不是面向对象语言,面向原型语言 prototype
es6 面向对象 class
2
3
4
5
6
7
8
%/accordion%
%accordion% 三种法🚀 %accordion%
// 1、函数
function person(){//函数
}
person()
// 2、构造函数、类
function Person(){//以前:构造函数 //现在:类
}
new Person()
// 3、类、构造函数(es6)
class Person{//类
constructor(){//构造函数
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
简单定义一个函数
// function person() {//函数
// this.name = "小明"// 给window加
// }
function person() {//以前:构造函数 //现在:类
this.name = "小明"
}
var p = new person()//对象
console.log(p); //person {name: "小明"}
2
3
4
5
6
7
8
9
%/accordion%
# 二、类的创建方式
# 1、工厂模式,生产出来的所有实例化对象都是一样
function Car(){
this.name = "奔驰"
this.color = "black"
}
let a = new Car()
let b = new Car()
console.log(a)
console.log(b)
2
3
4
5
6
7
8
9
%accordion% 克隆工厂模式🚀 %accordion%
function person() {//构造函数/类
this.name = "小明"
}
var p1 = new person()//对象
console.log(p1); //person {name: "小明"}
var p2 = new person()//对象
console.log(p2); //person {name: "小明"}
2
3
4
5
6
7
8
%/accordion%
# 2、实例化模式,复用性差,没有共性
function Car(name,color){//实例化模式,复用性差
this.name = name
this.color = color
}
let a = new Car("奔驰","黑色")
let b = new Car("宝马","蓝色")
console.log(a)
console.log(b)
2
3
4
5
6
7
8
9
%accordion% 实例化模式🚀 %accordion%
function person(name) {//构造函数/类
this.name = name
}
var p1 = new person("小明")//对象
console.log(p1); //person {name: "小明"}
var p2 = new person("小红")//对象
console.log(p2); //person {name: "小红"}
2
3
4
5
6
7
%/accordion%
# 3、基于原型的混合模式,同时具有共性和特性
function Car(name){
this.name = name
}
Car.prototype.color = "黑色"
let a = new Car("奔驰")
let b = new Car("宝马")
console.log(a)
console.log(b)
2
3
4
5
6
7
8
9
10
%accordion% 混合模式,同时具有共性和特性🚀 %accordion%
function person(name, age, sex) {//构造函数/类
this.name = name
this.age = age
this.sex = sex
}
person.prototype.country = "中国"//共性(原型去添加)
var p1 = new person("小明", 18, "男")//特性
console.log(p1); //person {name: "小明", age: 18, sex: "男"}
var p2 = new person("小红", 23, "女")//特性
console.log(p2); //person {name: "小红", age: 18, sex: "男"}
2
3
4
5
6
7
8
9
10
11
12
13
这种仅参考
function person(name, age, sex, country) {//构造函数/类
this.name = name
this.age = age
this.sex = sex
this.country = country
}
var p1 = new person("小明", 18, "男", "中国")//对象
console.log(p1); //person {name: "小明", age: 18, sex: "男", country: "中国"}
var p2 = new person("小红", 23, "女", "中国")//对象
console.log(p2); //person {name: "小红", age: 18, sex: "男", country: "中国"}
2
3
4
5
6
7
8
9
10
11
%/accordion%
# 三、实例化对象、构造函数、原型
[warning] For warning
所有引用类型都有一个
__proto__(隐式原型)属性,属性值是一个普通的对象。所有函数都有一个__prototype__(原型)属性,属性值是一个普通的对象。
所有引用类型的
__proto__属性指向它构造函数的__prototype__。
function Car(){//构造函数
this.name = "奔驰"
this.color = "black"
}
let a = new Car()
console.log(a)//实例化对象
console.log(a.__proto__)//实例化对象a的原型
console.log(Car.prototype)//实例化对象a的原型
console.log(a.__proto__ === Car.prototype)//true
2
3
4
5
6
7
8
9
10
11
12
# 四、原型链
[!NOTE]
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的
__proto__隐式原型上查找,即它的构造函数的__prototype__,如果还没有找到就会再在构造函数的__prototype__的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。
function Car(){//构造函数
this.name = "奔驰"
this.color = "black"
}
let a = new Car()
console.log(a.__proto__)//实例化对象a的原型。即Car.prototype
console.log(a.__proto__.__proto__)//对象Object的原型。即Object.prototype
console.log(a.__proto__.__proto__.__proto__)//null
2
3
4
5
6
7
8
9
{% reveal text="图片块" %}

{% endreveal %}
类\\构造函数
1、prototype -> 访问原型
2、__proto__ -> 指针,访问构造这个类的原型
原型
1、prototype -> 访问原型
2、__proto__ -> 指针,访问构造这个原型的原型
3、constructor -> 访问类\\构造函数
实例化对象
1、__proto__ -> 指针,访问构造这个实例化对象的原型
2、constructor -> 访问类\\构造函数
2
3
4
5
6
7
8
9
10
11
12
[!cogs]
%accordion% 练习 %accordion%
function Person(name) {//类、构造函数
this.name = name//实例属性
}
var p = new Person("小明")
// console.log(Person.prototype);
// console.log(Person.__proto__.constructor);//指针,指向构造这个类的原型
// console.log(Person.__proto__.__proto__);
// console.log(person.__proto__.__proto__.__proto__);//null
Person.__proto__.__proto__.constructor.prototype.eyes = 3
Person.prototype.eyes = 3
console.log(p.eyes);//3
2
3
4
5
6
7
8
9
10
11
12
13
14
15
%/accordion%
# 五、对象的方法
//返回指定对象的原型,用来代替__proto__
Object.getPrototypeOf(obj)
//在对象自身查找属性而不到原型上查找
hasOwnProperty()
//判断一个对象是否是某个实例的原型对象
isPrototypeOf
//判断一个对象是否是一个类的实例
instanceof
//根据__proto__来创建一个新对象
Object.create()
//用于将所有可枚举属性的值从一个或多个源对象复制到目标对象
Object.assign()
//案例
function Car(name){
this.name = name
}
Car.prototype.color = "黑色"//原型属性(共性)
let a = new Car("奔驰")
console.log(a.hasOwnProperty("name"))//true
console.log(a.__proto__.isPrototypeOf(a))//true
console.log(a instanceof Car)//true
let b = Object.create(a.__proto__)//创建一个基于原型的新对象
console.log(b)
let obj = {name:"小明"}
let obj2 = {name:"小红"}
console.log(Object.assign(obj,obj2))
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 六、堆和栈
//堆 存储引用类型数据object(函数,数组等都是)
//栈 存储普通类型数据number,string,boolean,undefined,null
//栈是直接赋值数据,堆是赋值引用地址
//栈类型数据
var a = "123"
var b = a
b = "456"
console.log(a)//123
console.log(b)//456
//堆类型数据
var a = {"name":"小明"}
var b = a
b.name = "小红"
console.log(a)//{name: "小红"}
console.log(b)//{name: "小红"}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
%accordion% 堆和栈的区别 %accordion%
堆和栈
栈是直接赋值数据:速度快
堆是赋值引用地址:速度慢
堆: 粘贴 文件a(10mb) 文件b(10,mb)
栈: 粘贴快捷方式 文件a(10mb) 文件b(5kb)
2
3
4
5
6
直接赋值 【栈】
var a = 1
var b = a
b = 2
console.log(a); //1
console.log(b); //2
2
3
4
5
赋值的是引用地址,CPU地址 对象 【堆】
var a = { name: "小明" }
var b = a;
b.name = "小红"
console.log(a); //小红
console.log(b); //小红
2
3
4
5
%/accordion%
# 1)浅克隆和深克隆
# 浅克隆,只克隆对象的第一层属性
var obj = {name:"小明"}
var obj2 = Object.assign({},obj)
obj2.name = "小红"
console.log(obj) //{name: "小明"}
console.log(obj2) //{name: "小红"}
2
3
4
5
%accordion% 浅克隆——更改值另一个不受影响 %accordion%
var a = {
name: "小明1",
obj: {
name: "小明2"
}
}
var b = Object.assign({}, a)
b.obj.name = "小红"
console.log(a);
console.log(b);
2
3
4
5
6
7
8
9
10

%/accordion%
# 深克隆,克隆对象的所有层级的属性
[warning] 深克隆有三种方法
1、自定义深克隆——麻烦
2、JSON.parse(JSON.stringify())——缺陷
3、jq方法 $.extend(true,{},obj)——引用函数库
[!cogs]
%accordion% 简单深克隆 %accordion%
var a = {
name: "小明1",
obj: {
name: "小明2"
}
}
var x = Object.assign({}, a)
var y = Object.assign({}, a.obj)
x.obj = y
x.obj.name = "小红2"
console.log(x);
console.log(a);
2
3
4
5
6
7
8
9
10
11
12

%/accordion%
%accordion% 1、自定义深克隆 %accordion%
function deepClone(obj){
var x = {}
for(key in obj){
if(typeof obj[key] === "object"){
x[key] = deepClone(obj[key])
}else{
x = Object.assign(x,obj)
}
}
return x
}
var b = deepClone(a)
b.obj.name = "小红2"
console.log(a)//{name: "小明1",obj: {name: '小明2'}}
console.log(b)//{name: "小明1",obj: {name: '小红2'}}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

%/accordion%
%accordion% 2、JSON.parse(JSON.stringify()) %accordion%
工作中用得最多了
缺陷里面有——构造涵数、正则表达式 都会有问题
var a = {
name: "小明1",
obj: {
name: "小明2"
}
}
var b = JSON.parse(JSON.stringify(a))
b.obj.name = "小红"
console.log(a);
console.log(b);
2
3
4
5
6
7
8
9
10

%/accordion%
%accordion% 3、jq方法 $.extend(true,{},obj) 引用函数库 %accordion%
# jquery (opens new window)
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
var a = {
name: "小明1",
obj: {
name: "小明2"
},
reg: /hello/
}
var b = $.extend(true, {}, a)
b.obj.name = "小红2"
console.log(a);
console.log(b);
2
3
4
5
6
7
8
9
10
11
12
13

%/accordion%
# 2)类的继承
es5
//es5
function Person(){
this.name = "小明"
}
Person.prototype.age = 18
var p = new Person()
function Student(){
Person.call(this)
}
Student.prototype = Person.prototype
var s = new Student()
console.log(s.age)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
es6 ——方便
class Person{
constructor(name){
this.name = name
}
}
var p = new Person("小明")
class Student extends Person{
constructor(name){
super(name)
}
}
var s = new Student("小红")
console.log(s)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16