class People {
constructor(name, age) {
this.name = name
this.age = age
}
eat() {
console.log(`${this.name} eat something`)
}
speak() {
console.log(`My name is ${this.name}, age ${this.age}`)
}
}
let zhang = new People('zhang', 20)
zhang.eat()
zhang.speak()
let wang = new People('wang', 21)
wang.eat()
wang.speak()
三要素:继承封装多态
继承:子类继承父类
继承是父类,公共的,不仅仅服务于 Student
继承可将公共方法抽离出来,提高复用,减少冗余
封装:数据的权限和保密
public 完全开放
protected 对子类开放
private 对自己开放
ES6不支持,可以用 typescript 演示
减少耦合,不该外露的不外露
利于数据、接口权限的管理
ES6 目前不支持,一般认为_开头的属性是私有的
多态:同一接口不同实现
JS 应用少
保持子类的开放性和灵活性
面向接口编程
// 继承
class People {
constructor(name, age) {
this.name = name
this.age = age
}
eat() {
console.log(`${this.name} eat something`)
}
speak() {
console.log(`My name is ${this.name}, age ${this.age}`)
}
}
class Student extends People {
constructor(name, age, number) {
super(name, age)
this.number = number
}
study() {
console.log(`${this.name} study`)
}
}
let xiaoming = new Student('xiaoming', 10, 'A1')
xiaoming.study()
console.log(xiaoming.number)
let xiaohong = new Student('xiaohong', 11, 'A2')
xiaohong.study()
// 多态
class People {
constructor(name) {
this.name = name
}
saySomething() {
}
}
class A extends People {
constructor(name) {
super(name)
}
saySomething() {
console.log('I am A')
}
}
class B extends People {
constructor(name) {
super(name)
}
saySomething() {
console.log('I am B')
}
}
let a = new A('a')
a.saySomething()
let b = new B('b')
b.saySomething()
JS 应用举例
class jQuery {
constructor(selector) {
let slice = Array.prototype.slice
let dom = slice.call(document.querySelectorAll(selector))
let len = dom ? dom.length : 0
for (let i = 0; i < len; i++) {
this[i] = dom[i]
}
this.length = len
this.selector = selector || ''
}
append(node) {
}
addClass(name) {
}
html(data) {
}
// 此处省略若干 API
}
window.$ = function(selector) {
return new jQuery(selector)
}
面向对象的意义
程序执行:顺序、判断、循环——结构化
面向对象:数据结构化
对于计算机,结构化的才是最简单的
编程应该 简单 & 抽象
UML类图
统一建模语言。
类图:UML 包含很多种图,本次相关的是类图
关系:主要讲解泛化和关联
泛化表示继承,关联表示引用
类图:
关系:
设计原则
什么是设计
即按照哪一种思路或者标准来实现功能
功能相同,可以有不同设计方案来实现
伴随着需求增加,设计的作用才能体现出来
UNIX / LINUX 设计哲学
准则1:小即是美
准则2:让每个程序只做好一件事
准则3:快速建立原型
准则4:舍弃高效率而取可移植性
准则5:采用纯文本来存储数据
准则6:软件复用
准则7:使用 shell 脚本来提高杠杆效应和可移植性
准则8:避免强制性的用户界面
准则9:让每个程序都称为过滤器
小准则:允许用户定制环境
尽量使操作系统内核小而轻量化
使用小写并尽量简短
沉默是金
SOLID五大设计原则
S 单一职责
一个程序只做好一件事
如果功能过于复杂就拆分开,每个部分保持独立
O 开放封闭
对扩展开放,对修改封闭
增加需求,扩展新代码,而非修改已有代码
这是软件设计的终极目标
L 李氏置换
子类能覆盖父类
父类能出现的地方子类就能出现
JS 中使用较少(弱类型&继承使用较少)
I 接口独立
保持接口的单一独立,避免出现“胖接口”
JS 中没有接口(typescript 例外),使用较少
类似于单一职责原则,这里更关注接口
D 依赖倒置
面向接口编程,依赖于抽象而不依赖于具体
使用方只关注接口而不关注具体类实现
JS 中使用较少(没有接口&弱类型)
设计模式
从设计到模式
创建型
工厂模式
单例模式
原型模式
结构型
适配器模式
装饰器模式
代理模式
外观模式
桥接模式
组合模式
享元模式
行为型
策略模式
迭代器模式
模板方法模式
职责连模式
观察者模式
命令模式
备忘录模式
状态模式
访问者模式
中介者模式
解释器模式
明白每个设计的道理和用意
通过经典应用体会它的真正使用场景
自己编码时多思考,尽量模仿
两个面试题
01
class Car {
constructor(number, name) {
this.number = number
this.name = name
}
}
class Kuaiche extends Car {
constructor(number, name) {
super(number, name)
this.price = 1
}
}
class Zhuanche extends Car {
constructor(number, name) {
super(number, name)
this.price = 2
}
}
class Trip {
constructor(car) {
this.car = car
}
start() {
console.log(`行程开始,名称: ${this.car.name}, 车牌号: ${this.car.price}`)
}
end() {
console.log('行程结束,价格: ' + (this.car.price * 5))
}
}
let car = new Kuaiche(100, '桑塔纳')
let trip = new Trip(car)
trip.start()
trip.end()
02
// 车
class Car {
constructor(num) {
this.num = num
}
}
// 入口摄像头
class Camera {
shot(car) {
return {
num: car.num,
inTime: Date.now()
}
}
}
// 出口显示器
class Screen {
show(car, inTime) {
console.log('车牌号', car.num)
console.log('停车时间', Date.now() - inTime)
}
}
// 停车场
class Park {
constructor(floors) {
this.floors = floors || []
this.camera = new Camera()
this.screen = new Screen()
this.carList = {}
} in (car) {
// 获取摄像头的信息:号码 时间
const info = this.camera.shot(car)
// 停到某个车位
const i = parseInt(Math.random() * 100 % 100)
const place = this.floors[0].places[i]
place.in()
info.place = place
// 记录信息
this.carList[car.num] = info
}
out(car) {
// 获取信息
const info = this.carList[car.num]
const place = info.place
place.out()
// 显示时间
this.screen.show(car, info.inTime)
// 删除信息存储
delete this.carList[car.num]
}
emptyNum() {
return this.floors.map(floor => {
return `${floor.index} 层还有 ${floor.emptyPlaceNum()} 个车位`
}).join('\n')
}
}
// 层
class Floor {
constructor(index, places) {
this.index = index
this.places = places || []
}
emptyPlaceNum() {
let num = 0
this.places.forEach(p => {
if (p.empty) {
num = num + 1
}
})
return num
}
}
// 车位
class Place {
constructor() {
this.empty = true
} in () {
this.empty = false
}
out() {
this.empty = true
}
}
// 测试代码------------------------------
// 初始化停车场
const floors = []
for (let i = 0; i < 3; i++) {
const places = []
for (let j = 0; j < 100; j++) {
places[j] = new Place()
}
floors[i] = new Floor(i + 1, places)
}
const park = new Park(floors)
// 初始化车辆
const car1 = new Car('A1')
const car2 = new Car('A2')
const car3 = new Car('A3')
console.log('第一辆车进入')
console.log(park.emptyNum())
park.in(car1)
console.log('第二辆车进入')
console.log(park.emptyNum())
park.in(car2)
console.log('第一辆车离开')
park.out(car1)
console.log('第二辆车离开')
park.out(car2)
console.log('第三辆车进入')
console.log(park.emptyNum())
park.in(car3)
console.log('第三辆车离开')
park.out(car3)
工厂模式
介绍
UML && 代码演示
使用场景
介绍:
将 new 操作单独封装
遇到 new 时,就要考虑是否该用工厂模式
class Product {
constructor(name) {
this.name = name
}
init() {
}
fun1() {
}
}
class Creator {
create(name) {
return new Product(name)
}
}
// test
let creator = new Creator()
let p1 = creator.create('p1')
p1.init()
class Adaptee {
specificRequest() {
return '德国标准插头'
}
}
class Target {
constructor() {
this.adaptee = new Adaptee()
}
request() {
let info = this.adaptee.specificRequest()
return `${info} - 转换器 - 中国标准插头`
}
}
// 测试代码
let target = new Target()
let res = target.request()
console.log(res)
// 装饰类
// @testable
// class MyTestableClass {
// // ...
// }
// function testable(target) {
// target.isTestable = true;
// }
// console.log(MyTestableClass.isTestable) // true
function mixins(...list) {
return function (target) {
Object.assign(target.prototype, ...list)
}
}
const Foo = {
foo() { console.log('foo') }
}
@mixins(Foo)
class MyClass {}
let obj = new MyClass();
obj.foo() // 'foo'
// 装饰方法
function readonly(target, name, descriptor) {
// descriptor对象原来的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
}
class Person {
constructor() {
this.first = 'A'
this.last = 'B'
}
@readonly
name() {
return `${this.first} ${this.last}` }
}
var p = new Person()
console.log(p.name())
p.name = function() {} // 这里会报错,因为 name 是只读属性
// another
function log(target, name, descriptor) {
var oldValue = descriptor.value;
descriptor.value = function() {
console.log(`Calling ${name} with`, arguments);
return oldValue.apply(this, arguments);
};
return descriptor;
}
class Math {
@log
add(a, b) {
return a + b;
}
}
const math = new Math();
const result = math.add(2, 4);
console.log('result', result);
// core-decorators
// import { readonly } from 'core-decorators'
// class Person {
// @readonly
// name() {
// return 'zhang'
// }
// }
// let p = new Person()
// console.log(p.name())
// // p.name = function () { /*...*/ } // 此处会报错
import { deprecate } from 'core-decorators';
class Person {
@deprecate
facepalm() {}
@deprecate('We stopped facepalming')
facepalmHard() {}
@deprecate('We stopped facepalming', { url: 'http://knowyourmeme.com/memes/facepalm' })
facepalmHarder() {}
}
let person = new Person();
person.facepalm();
// DEPRECATION Person#facepalm: This function will be removed in future versions.
person.facepalmHard();
// DEPRECATION Person#facepalmHard: We stopped facepalming
person.facepalmHarder();
// DEPRECATION Person#facepalmHarder: We stopped facepalming
//
// See http://knowyourmeme.com/memes/facepalm for more details.
设计原则验证:
将现有对象和装饰器进行分离,两者独立存在
符合开放封闭原则
代理模式
介绍:
使用者无权访问目标对象
中间加代理,通过代理做授权和控制
例子:
科学上网
明星经纪人
UML类图:
演示:
场景:
网页事件代理
jQuery $.proxy
ES6 Proxy
// 明星
let star = {
name: '张XX',
age: 25,
phone: '13910733521'
}
// 经纪人
let agent = new Proxy(star, {
get: function(target, key) {
if (key === 'phone') {
// 返回经纪人自己的手机号
return '18611112222'
}
if (key === 'price') {
// 明星不报价,经纪人报价
return 120000
}
return target[key]
},
set: function(target, key, val) {
if (key === 'customPrice') {
if (val < 100000) {
// 最低 10w
throw new Error('价格太低')
} else {
target[key] = val
return true
}
}
}
})
// 主办方
console.log(agent.name)
console.log(agent.age)
console.log(agent.phone)
console.log(agent.price)
// 想自己提供报价(砍价,或者高价争抢)
agent.customPrice = 150000
// agent.customPrice = 90000 // 报错:价格太低
console.log('customPrice', agent.customPrice)
访问代理,接口地址是不会变的。
设计原则验证:
代理类和目标类分离,隔离开目标类和使用者
符合开放封闭原则
代理模式 VS 适配器模式
适配器模式:提供一个不同的接口
代理模式:提供一模一样的接口
代理模式 VS 装饰器模式
装饰器模式:扩展功能,原有功能不变且可直接使用
代理模式:显示原有功能,但是经过限制或者阉割之后的
外观模式
介绍:
为子系统中的一组接口提供了一个高层接口
使用者使用这个高层接口
观察者模式
介绍:
发布 & 订阅
一对多
UML类图:
例子:
点咖啡,点好后坐等被叫
// 主题,接收状态变化,触发每个观察者
class Subject {
constructor() {
this.state = 0
this.observers = []
}
getState() {
return this.state
}
setState(state) {
this.state = state
this.notifyAllObservers()
}
attach(observer) {
this.observers.push(observer)
}
notifyAllObservers() {
this.observers.forEach(observer => {
observer.update()
})
}
}
// 观察者,等待被触发
class Observer {
constructor(name, subject) {
this.name = name
this.subject = subject
this.subject.attach(this)
}
update() {
console.log(`${this.name} update, state: ${this.subject.getState()}`)
}
}
// 测试代码
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)
let o3 = new Observer('o3', s)
s.setState(1)
s.setState(2)
s.setState(3)
JS 设计模式
面向对象
搭建开发环境
npm / webapck / webpack-dev-server / babel babel-core babel-loader babel-polyfill babel-preset-env
什么是面向对象
概念 类(对象的模板)、对象(实例)
三要素:继承封装多态
JS 应用举例
面向对象的意义
UML类图
统一建模语言。
关系:
设计原则
设计模式
从设计到模式
创建型
结构型
行为型
明白每个设计的道理和用意
通过经典应用体会它的真正使用场景
自己编码时多思考,尽量模仿
两个面试题
01
02
工厂模式
介绍:
场景:
学习经典库的方法:
设计原则验证:
单例模式
介绍:
登陆框、购物车...
说明:
场景:
jQuery
设计原则验证:
适配器模式
插头,转接口...
介绍:
UML类图:
演示:
场景:
设计原则验证:
装饰器模式
介绍:
例子:手机壳
UML类图:
ES7 装饰器 babel插件:babel-plugin-transform-decorators-legacy 库:core-decorators(常用装饰器已经写好了,直接拿来用)
设计原则验证:
代理模式
介绍:
例子:
UML类图:
演示:
场景:
访问代理,接口地址是不会变的。 设计原则验证:
代理模式 VS 适配器模式
代理模式 VS 装饰器模式
外观模式
介绍:
观察者模式
介绍:
UML类图:
例子:
场景:
node Stream 用到了自定义事件:
其他场景:
设计原则验证:
迭代器模式
介绍:
UML类图:
使用 jQuery 示例:
使用场景:
为何 ES6 Iterator 存在?
ES6 Iterator 是什么?
ES6 Iterator 示例:
ES6 Iterator 与 Generator
设计原则验证:
状态模式
介绍:
UML类图:
场景:
设计原则验证:
其他设计模式
原型模式
桥接模式
组合模式
享元模式(共享元数据)
例子:事件代理(ul>li)
策略模式
模板方法模式
职责链模式
命令模式
备忘录模式
编辑器案例:备忘列表存储编辑器中设置的每一项设置的内容
中介者模式
联想现实中介。1
访问者模式&解释器模式
略
关于面试
重点设计模式要深入理解 非常用的,视业务场景需要选择
综合应用
介绍:
UML类图: