JavaScript OOP

什么是面向对象?

“面向对象”是一种编程范型,但是就像 exist 这个选项一样,我们还有很多其他的选择,比如函数式编程,响应式编程编程等等。

这一范式的特点是什么?

我们在这个范例中所做的是以一种更接近现实的方式进行编程,我们根据类、对象、方法、属性等等进行编程,特别是集成了抽象、封装、模块
化、隐私、多态、继承等术语。

基于类和基于原型的语言都是面向对象程序设计语言的范式,经典的C#与JAVA就是基于类面向对象的,JavaScript面向对象是基于原型的。

在 ES5中,我们可以使用工厂模式进行下一个示例:

1
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
40
41
42

console.log('*** PERSON ***');
function Person (name) {
this.name = name;
}
// 定义Person对象的属性和方法
Person.prototype = {
eyes: 2,
month: 1,
sleep: function () {
return 'zzz';
}
};
// 创建 Person 对象
const p1 = new Person('OldWang');
// 尝试打印:
console.log(
`name: ${p1.name}`,
`eyes: ${p1.eyes}`,
`month: ${p1.month}`,
p1.sleep()
);
console.log('*** EMPLOYEE ***')
// 但是现在,如果我们有一个Employee类,我们就可以继承该人的财产。
function Employee (name, salary) {
this.name = name;
this.salary = salary;
}
// 实现继承
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee; // 设置Employee的构造函数
// So now, we just can do the same thing
// 创建我们的员工
const em1 = new Employee('tom', 3000);
// 员工信息:
console.log(
`name: ${em1.name}`,
`salary: ${em1.salary} RMB`,
`eyes: ${em1.eyes}`,
`month: ${em1.month}`,
em1.sleep()
);

现在,在ES6中,我们可以用一种简单的方式来完成所有这些操作,但是我们必须记住,这只是语法糖:

1
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
class Person {
constructor (name) {
this.name = name;
this.eyes = 2;
this.month = 1;
}
sleep () {
return 'zzz';
}
}

class Employee extends Person {
constructor (name, salary) {
super(name);
this.salary = salary;
}
}

const p1 = new Person('Nick');

console.log(
`name: ${p1.name}`,
`eyes: ${p1.eyes}`,
`month: ${p1.month}`,
p1.sleep()
);

const em1 = new Employee('John', 3000);

console.log(
`name: ${em1.name}`,
`salary: ${em1.salary} USD`,
`eyes: ${em1.eyes}`,
`month: ${em1.month}`,
em1.sleep()
);

在这种情况下,使用 extends 关键字,我们只需说: ‘好吧,我想继承 Person 类的产品’。 但在幕后,这与我们在 es5示例中使用原型所做的是一样的。


静态方法

1
2
3
4
5
6
7
class Dog {
static whatIs() {
return '一种可爱的动物';
}
}
// 使用静态方法,我们无需实例化类的新对象即可访问方法。实例化调用反而会报错🐛
console.log( Dog.whatIs() );

私有方法

在 JavaScript 中,我们没有像 JavaC# 那样的 private 关键字,重要的是在 JavaScript 中,我们有一个用于 private 值的约定, 这个约定是在单词之前使用一个下划线 _ 让我展示给你看:

1
2
3
4
5
6
7
8
9
10

class Person {
constructor (name, phone) {
this.name = name;
this._phone = phone;
}
}
const p1 = new Person('John', 544342212);
// 因为js没有private所以,可以打印出来
console.log(p1._phone);

ES6中,我们有一个对象调用WeakMap,我们可以用他创建私有属性,让我们看看:

1
2
3
4
5
6
7
8
9
10
const secret = new WeakMap();
class Person {
constructor (name, phone) {
this.name = name;
secret.set(this, {_phonenumber: phone});
}
}
const p1 = new Person('John', 544342212);
// 现在无法访问
console.log(p1._phonenumber); // undefined

GET&SET

当我们有私有属性时,通常会创建一个返回私有值的公有方法,因此我们必须返回一个值并设置一个新值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const secret = new WeakMap();
class Person {
constructor (name, phone) {
this.name = name;
secret.set(this, {_phonenumber: phone});
}
get phoneNumber() {
return secret.get(this)._phonenumber;
}
set phoneNumber(newNumber) {
secret.get(this)._phonenumber = newNumber;
}
}

const p1 = new Person('John', 544342212);
// 现在,我们可以使用getter来访问电话号码:
console.log(p1.phoneNumber); // 544342212
p1.phoneNumber = 432232323;
console.log(p1.phoneNumber); // 432232323

多态

多态(Polymorphism)是指由继承而产生的相关的不同的类,其对象对同一消息会做出不同的响应。

我们先用ES5原型来实现多态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

var makeSound = function(animal) {
animal.sound();
}

var Duck = function(){}
Dog.prototype.sound = function() {
console.log('汪汪汪')
}
var Chiken = function() {};
Chiken.prototype.sound = function() {
console.log('咯咯咯')
}

makeSound(new Dog()); // 汪汪汪
makeSound(new Chicken()); // 咯咯咯

接下来用Class来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

class Animal{
cry(){};
}

class Dog extends Animal{
static cry(){
return '汪汪汪';
}
}

class Chiken extends Animal{
static cry(){
return '咯咯咯';
}
}
console.log(Dog.cry()); // 汪汪汪
console.log(Chiken.cry());// 咯咯咯

资源

面向对象程序设计

Thanks for watching!😉