目录
一.面向对象简介
面向对象是一种思想,和具体的语言一样,与面向过程对比如下:
-
面向过程:思考的切入点是功能的步骤
-
面向对象:思考的切入点是对象的划分
【例1】分别用面向对象和面向过程来描述把大象装冰箱的步骤
面向过程
//1.把冰箱门打开
function openFrige() {
}
openFrige();
//2.把大象装进去
function ElephantIn() {
}
ElephantIn();
//3.把冰箱门关上
function closeFrige() {
}
closeFrige();
面向对象
//1.创建一个大象类
function Elephant() {
}
//2.创建一个冰箱类
function Frige() {
}
//3.在冰箱类上添加开门的方法
Frige.prototype.openDoor = function () {
}
//4.在冰箱类上添加关门的方法
Frige.prototype.closeDoor = function () {
}
//5.在冰箱类上添加装东西的方法
Frige.prototype.join = function (things) {
this.openDoor();
//装东西的操作
this.closeDoor;
}
var frig = new Frige();
frig.join(new Elephant());
二.类(构造函数的语法糖)
1.传统的构造函数的问题
(1)属性和原型方法定义分离,降低了可读性
(2)原型成员可以被枚举
(3)默认情况下,构造函数仍然可以被当作普通函数使用
【例2-1】
function Animal(type, name, sex, age) {
this.type = type;
this.name = name;
this.sex = sex;
this.age = age;
}
Animal.prototype.print = function () {
console.log(`种类:${this.type}`);
console.log(`姓名:${this.name}`);
console.log(`性别:${this.sex}`);
console.log(`年龄:${this.age}`);
}
const a = new Animal('狗', '旺财', '公', '3');
a.print();
for (const prop in a) {
console.log(prop)
}
【结果】
![](https://i-blog.csdnimg.cn/blog_migrate/f026786cf2a74c5b721b732e1494540d.png)
2.类的特点
(1)类声明不会被提升,与let和const一样,存在暂时性死区
(2)类中的所有代码均在严格模式执行
(3)类的所有方法都是不可枚举的
(4)类的所有方法都无法被当作构造函数使用
(5)类的构造器必须使用new来调用
【例2-2】
class Animal {
constructor(type, name, age, sex) {
this.type = type;
this.name = name;
this.age = age;
this.sex = sex;
}
print() {
console.log(`种类:${this.type}`);
console.log(`姓名:${this.name}`);
console.log(`年龄:${this.age}`);
console.log(`性别:${this.sex}`);
}
}
const a = new Animal('狗', '旺财', '公', '3');
a.print();
for (const prop in a) {
console.log(prop);
}
【结果】
![](https://i-blog.csdnimg.cn/blog_migrate/a919d95c761634e3d53b3a8e471669d0.png)
三.类的其他书写方式
1.可计算的成员名
【例3-1】
const printName = 'print';
class Animal {
constructor(type, name, age, sex) {
this.type = type;
this.name = name;
this.age = age;
this.sex = sex;
}
[printName]() {
console.log(`【种类】:${this.type}`);
console.log(`【名字】:${this.name}`);
console.log(`【年龄】:${this.age}`);
console.log(`【性别】:${this.sex}`);
}
}
const a = new Animal("狗", "旺财", 3, "男");
a[printName]();
2.getter和setter
Object.defineProperty可以定义某个对象成员属性的读取和设置
使用getter和setter控制的属性,不在原型上
【例3-2】
const printName = 'print';
class Animal {
constructor(type, name, age, sex) {
this.type = type;
this.name = name;
this.age = age;
this.sex = sex;
}
//创建一个age属性,并给它加上getter,读取该属性时,会运行该函数
get age() {
return this._age + '岁';
}
//创建一个age属性,并给它加上setter,给该属性赋值时,回运行该函数
set age(age) {
if (typeof age !== "number") {
throw new Error('age property must be a number');
}
if (age<0) {
age = 0;
} else if(age>1000){
age = 1000;
}
this._age = age;
}
[printName]() {
console.log(`【种类】:${this.type}`);
console.log(`【名字】:${this.name}`);
console.log(`【年龄】:${this.age}`);
console.log(`【性别】:${this.sex}`);
}
}
const a = new Animal("狗", "旺财", -1, "公");
a[printName]();
const a1 = new Animal("乌龟", "拓拓", 1001, "公");
a1[printName]();
【结果】
![](https://i-blog.csdnimg.cn/blog_migrate/2be1194ca55489109c5540c806cfcdb2.png)
3.静态成员
静态成员指构造函数本身的成员,ES6中使用static关键字定义的成员即为静态成员
【例3-3】
class Chess {
constructor(name){
this.name = name;
}
static width = 50;
static method() {
console.log(`I'm a chess`);
}
}
const chess = new Chess('车');
console.log(chess);
console.log(Chess.width);
Chess.method()
【结果】
![](https://i-blog.csdnimg.cn/blog_migrate/0afb498e997cdac9179027d0db0a1ffd.png)
4.字段初始化器
(1)使用static的字段初始化器,添加的是静态成员
(2)没有使用static的字段初始化器,添加的成员位于对象上
(3)箭头函数在字段初始化器位置上,指向当前对象
【例4-1-1】
class Test {
static a = 1;
b = 2;
c = 3;
constructor() {
this.d = this.b + this.c;
}
}
const t = new Test();
console.log(t);
【结果】
![](https://i-blog.csdnimg.cn/blog_migrate/1da450b808d4f3129309c8de3ff10fe6.png)
【例4-1-2】
class Test {
constructor() {
this.a = 123;
}
print = () => {
console.log(this.a);
}
}
const t1 = new Test();
const t2 = new Test();
console.log(t1.print === t2.print);
【结果】打印false
5.类表达式
【例5】
//匿名类,类表达式
const A = class {
a = 1;
b = 2;
}
const a = new A()