面向对象
概念
- 三要素:继承 封装 多态
// 类,即模板
class People {
constructor(name, age) {
this.name = name
this.age = age
}
eat() {
alert(`${this.name} eat something`)
}
speak() {
alert(`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()
- 继承,子类继承父类
// 父类
class People {
constructor(name, age) {
this.name = name
this.age = age
}
eat() {
alert(`${this.name} eat something`)
}
speak() {
alert(`My name is ${this.name}, age ${this.age}`)
}
}
// 子类继承父类
class Student extends People {
constructor(name, age, number) {
super(name, age)
this.number = number
}
study() {
alert(`${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()
1.people是父类,公共的,不仅仅服务于student
2.继承可将公共方法抽离出来,提高复用,减少冗余
- 封装,数据的权限和保密
1.public 完全开放
2.protected 对子类开放
3.private 对自己开放
class Student extends People {
number
private girlfriend
constructor(name, age, number) {
super(name, age)
this.number = number
this.girlfriend = 'xiaoli'
}
study() {
alert(`${this.name} study`)
}
}
1.减少耦合,不该露的不外露
2.利于数据,接口的权限管理
3.es6目前不支持,需要typescript支持,目前一般认为_开头的方法为私有
- 多态,统一接口不同实现
1.保持子类的开放性和灵活性,面向接口编程,js应用极少
2.需要结合java等语言的接口、重写、重载等功能
js的应用举例
// jquery模拟
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)
}
面向对象的意义
1.程序执行:顺序、判断、循环---结构化
2.面向对象 ---数据结构化
3.对于计算机,结构化的才是最简单的
4.编程应该 简单&抽象
设计原则
描述
- 即按照哪一种思路或者标准来实现功能
- 功能相同,可以有不同设计方案来实现
- 随着需求的增加,设计的作用才能体现出来
UNIX/LINUX设计哲学
- 准则1:小即是美
- 准则2:让每个程序只做好一件事
- 准则3:快速建立原型
- 准则4:舍弃高效率而取可移植性
- 准则5:采用纯文本来储存数据
- 准则6:充分利用软件的杠杆效应(软件复用)
- 准则7:使用shell脚本来提高杠杆效应和可移植性
- 准则8:避免强制性的用户界面
- 准则9:让每个程序都称为过滤器
- 小准则:允许用户定制环境
- 小准则:尽量使操作系统内核小而轻量化
- 小准则:使用小写字母并尽量简短
- 小准则:沉默是金
- 小准则:各部分之和大于整体
- 小准则:寻求90%的解决方案
S O L I D 五大设计原则
- S - 单一职责原则
1.一个程序只做好一件事
2.如果功能过于复杂就拆分开,每个部分保持独立 - O - 开放封闭原则
1.对扩展开放,对修改封闭
2.增加需求时,扩展新代码,而非修改已有代码
3.这是软件设计的终极目标 - L - 李氏置换原则
1.子类能覆盖父类
2.父类能出现的地方子类就能出现
3.js中使用较少(弱类型&继承使用较少) - I - 接口独立原则
1.保持接口的单一独立,避免出现“胖接口”
2.js中没有接口(typescript例外),使用较少
3.类似于单一职责原则,这里更关注接口 - D - 依赖导致原则
1.面向接口编程,依赖于抽象而不依赖于具体
2.使用方只关注接口而不关注具体类的实现
3.js中使用较少(没有接口&弱类型)
23种设计模式介绍
创建型
- 工厂模式(工厂方法模式,抽象工厂模式,建造者模式)
- 单例模式
- 原型模式
结构型
- 适配器模式
- 装饰器模式
- 代理模式
- 外观模式
- 桥接模式
- 组合模式
- 享元模式
行为型
- 策略模式
- 迭代器模式
- 模板方法模式
- 职责链模式
- 观察者模式
- 命令模式
- 备忘录模式
- 中介者模式
- 状态模式
- 解释器模式
- 访问者模式
设计模式详解
工厂模式
- 将new操作单独封装
- 遇到new时,就要考虑是否使用工厂模式
示例
- 你去购买汉堡,直接点餐、取餐,不会自己亲手做
- 商店要“封装”做汉堡的工作,做好直接给买者
class Product {
constructor (name) {
this.name = name
}
init() {
alert("init")
}
fun1() {
alert("fun1")
}
fun2() {
alert("fun1")
}
}
class Creator {
create (name) {
return new Product(name)
}
}
// 测试
let creator = new Creator()
let p = creator.create('p1')
p.init()
p.fun1()
单例模式
- 系统中被唯一使用
- 一个类只有一个实例
示例
- 登录框
- 购物车
class SingleObject {
login() {
console.log('login...')
}
}
SingleObject.getInstance = (function () {
let instance
return function () {
if (!instance) {
instance = new SingleObject();
}
return instance
}
})()
// 测试
let obj1 = SingleObject.getInstance()
obj1.login()
let obj2 = SingleObject.getInstance()
obj2.login()
console.log(obj1 === obj2)
class LoginForm {
constructor() {
this.state = 'hide'
}
show() {
if (this.state === 'show') {
alert('已经显示')
return
}
this.state = 'show'
console.log('登录框已显示')
}
hide() {
if (this.state === 'hide') {
alert('已经隐藏')
return
}
this.state = 'hide'
console.log('登录框已隐藏')
}
}
LoginForm.getInstance = (function () {
let instance
return function () {
if (!instance) {
instance = new LoginForm();
}
return instance
}
})()
// 一个页面中调用登录框
let login1 = LoginForm.getInstance()
login1.show()
// login1.hide()
// 另一个页面中调用登录框
let login2 = LoginForm.getInstance()
login2.show()
// 两者是否相等
console.log('login1 === login2', login1 === login2)
设计原则验证
- 符合单一职责原则,只实例化唯一的对象
- 没法具体开放封闭原则,但是绝对不违反开发封闭原则
适配器模式
介绍
- 旧接口格式和使用者不兼容
- 中间加一个适配器转换接口
实例

class Adaptee {
specificRequest() {
return '德国标准的插头'
}
}
class Target {
constructor () {
this.adaptee = new Adaptee()
}
request() {
let info = this.adaptee.specificRequest()
return `${info} -> 转换器 -> 中国标准的插头`
}
}
// 测试
let target = new Target()
target.request()
场景
- 封装旧接口
- vue computed
设计原则验证
- 将旧接口和使用者进行分离
- 符合开发封闭原则
装饰器模式
介绍
- 为对象添加新功能
- 不改变其原因的结构和功能
示例

场景
- es7装饰器
- core-decorators
代码示例
// 装饰类
//一个简单的demo
@testable
class MyTestableClass {
// ...
}
function testable(target) {
target.isTestable = true;
}
alert(MyTestableClass.isTestable) // true
// 装饰类 mixin 示例
function mixins(...list) {
return function (target) {
Object.assign(target.prototype, ...list)
}
}
const Foo = {
foo() { alert('foo') }
}
@mixins(Foo)
class MyClass {}
let obj = new MyClass();
obj.foo() // 'foo'
// 示例 只读装饰器
import { readonly } from 'core-decorators'
class Person {
@readonly
name() {
return 'zhang'
}
}
let p = new Person()
alert(p.name())
// p.name = function () { /*...*/ } // 此处会报错
// 打印日志装饰器
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
- 第三方开源lib
- 提供常用的装饰器
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.
设计原则验证
- 将现有对象和装饰器进行分离,两者独立存在
- 符合开发封闭原则
代理模式
介绍
- 使用者无权访问目标对象
- 中间加代理,通过代理做授权和控制
示例
- 科学上网,访问github.com
- 明星经纪人
// 明星
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)
观察者模式
介绍
- 发布&订阅
- 一对多
示例
- 点咖啡,点好之后坐等被叫
// 主题,接收状态变化,触发每个观察者
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)
场景
- 网页事件绑定
- promise
- jquery callbacks
- nodejs 自定义事件
<button id="btn1">btn</button>
$('#btn1').click(function () {
console.log(1);
})
$('#btn1').click(function () {
console.log(2);
})
$('#btn1').click(function () {
console.log(3);
})
网友评论