类理论
面向对象编程强调的是数据和操作数据的行为本质上是互相关联的,因此最好的设计就是把数据和它相关的行为封装起来。
例如:字符和字符串的关系,字符串是一串字符连接在一起,字符相当于数据,对字符串的操作是行为,通常会有计算字符串长度、添加、搜索等功能,所以被设计成了String类方法。
所有的字符串都是String类的一个实例,包含字符数据和可以应用到数据上的行为动作。
“类”设计模式 (编程风格)
面向对象的设计模式:
迭代器模式
、观察者模式
、工厂模式
、单例模式
等
还有一种变成风格是
过程化变成
JavaScript中的“类”
js中的“类”与其他语言上的类是不一样的(虽然ES6添加了一个class关键字),可以说js机制似乎一直在阻止你使用类的设计模式,只能说js中的“类”是一种
近似类
的机制。
类的机制
- 基本机制
- 类中存放一些变量,提供一些共有的了访问方法
- 使代码和数据(变量)进行交互(访问方法)
- 操作的实际上是类的实例化上的数据和方法(静态类成员除外)
建造
类其实就是相当于建造,
类
可以比作建筑中的蓝图
,类的实例
可以比作工人通过蓝图构建的实际建筑
。
类
就一个
(蓝图就一个
),但可以有多个实例
(实际建筑
可以根据蓝图构建出多个
)。
构造函数
class Person {
name = '';
// 构造函数
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
var person = new Person('Lee');
person.sayName();
类的继承
B类继承A类
,B类
为A类的子类
,A类
为B类的父类
class Father {
constructor(surname) {
this.surname = surname;
}
saySurname() {
console.log(this.surname);
}
}
class Son extends Father {
constructor(surname, name) {
super(surname);
this.name = name;
}
sayFullName() {
console.log(`${
this.name} - ${
this.surname}`);
}
}
var son = new Son('Lee', 'Prosper');
console.log(son.surname); // Lee
console.log(son.name); // Prosper
son.saySurname(); // Lee
son.sayFullName(); // Prosper - Lee
多态
多态的字面意思就是多种状态,同一操作作用于不同的对象上,可以产生不同的解释和不同的执行结果
class Animal {
say() {
console.log('Hello');
}
eat() {
console.log('动物用嘴吃饭-狼吞虎咽!!!');
}
}
class Person extends Animal {
eat() {
super.eat();
console.log('人用嘴吃饭-斯文的可以了!!!');
}
}
var person = new Person();
person.say(); // Hello
person.eat(); // 动物用嘴吃饭-狼吞虎咽!!! 人用嘴吃饭-斯文的可以了!!!
多重继承
js不支持多重继承,但可以借助别的手段实现(混入)
混入
混入模式(无论显式还是隐式)可以用来模拟类的复制行为,但是通常会产生丑陋并且脆 弱的语法,比如显式伪多态(OtherObj.methodName.call(this, …)),这会让代码更加难 懂并且难以维护。
显式混入
/**
* 简单的显示混入(其中name被重写了)
* source 要添加的对象
* target 最终对象
*/
function mixin(source, target) {
for (const key in source) {
if (!(key in target)) {
target[key] = source[key];
}
}
return target;
}
var lee = {
name: 'Tom',
age: 25,
say() {
console.log('Tom');
}
}
var person = mixin(lee, {
name: 'Lee', // 重写了lee中的name
hello() {
console.log('hello');
}
})
// {name: 'Lee', age: 25, say: ƒ(){Tom}, hello: ƒ(){hello}}
console.log(person);
- 寄生继承
function Father() { this.name = "Father"; } Father.prototype.say = function () { return 'Father'; } Father.prototype.hello = function () { return `Hello ${ this.say()}`; } // 寄生类, 寄生自Father function Son() { var father = new Father(); /** * Father { name: 'Father' } * Father.prototype { hello: ƒ (), say: ƒ () } */ console.log(father); console.log(father.hello()); // Hello Father father.age = 36; var hello = father.hello; // ƒ () { return `Hello ${this.say()}`; } // console.log(hello()); // err ---> this.say is not a function father.hello = function () { return hello.call(this); // this ---> father } console.log(father.hello()); // Hello Father return father; } var son = new Son(); /** * Father { name: 'Father', age: 36, hello: ƒ () { return hello.call(this); } } * Father.prototype { hello: ƒ () { return hello.call(this); }, say: ƒ () } */ console.log(son); console.log(son.say); // ƒ () { return 'Father'; } console.log(son.hello); // ƒ () { return hello.call(this); } console.log(son.hello()); // Hello Father
隐式混入
var Something = {
cool: function () {
this.greeting = "Hello World";
this.count = this.count ? this.count + 1 : 1;
}
};
Something.cool();
console.log(Something); // { cool: fun, greeting: "Hello World", count: 1 }
var Another = {
count: 1, // 因为自身自带count所以执行 `this.count + 1` 这段代码
cool: function () {
// 隐式把 Something 混入 Another
Something.cool.call(this);
}
};
Another.cool();
console.log(Another); // { cool: fun, greeting: "Hello World", count: 2 }