// 以下是立即执行的函数表达式
(function(){
var foo = 1
var bar = 2
console.log(foo * bar)
})()
// 携带参数
(function(foo, bar){
console.log(foo * bar)
})(1, 2)
// 闭包,访问函数内部的局部变量
var baz
(function(){
var foo = 1
var bar = 2
baz = function() {
return foo * bar
}
})()
baz()
组合模式(Composite Pattern)
特点:
层层嵌套,父节点 - 叶子节点
父节点和叶子节点有相同的接口以及不同的实现
class Container {
constructor(id) {
this.children = []
this.element = document.createElement('div')
this.element.id = id
this.element.style.border = '1px solid black'
this.element.style.margin = '10px'
this.element.classList.add('container')
}
add(child) {
this.children.push(child)
this.element.appendChild(child.getElement())
}
hide() {
this.children.forEach(node => node.hide())
this.element.style.display = 'none'
}
show() {
this.children.forEach(node => node.show())
this.element.style.display = ''
}
getElement() {
return this.element
}
}
class Text {
constructor(text) {
this.element = document.createElement('p')
this.element.innerText = text
}
add() {}
hide() {
this.element.style.display = 'none'
}
show() {
this.element.style.display = ''
}
getElement() {
return this.element
}
}
let header = new Container('header')
header.add(new Text('标题'))
header.add(new Text('logo'))
let main = new Container('main')
main.add(new Text('这是内容1'))
main.add(new Text('这是内容2'))
let page = new Container('page')
page.add(header)
page.add(main)
page.show()
document.body.appendChild(page.getElement())
适配器模式(Adapter Pattern)
In software engineering, the adapter pattern is a software design pattern (also known as wrapper, an alternative naming shared with the decorator pattern) that allows the interface of an existing class to be used as another interface. It is often used to make existing classes work with others without modifying their source code. --from wiki
In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other objects from the same class. --wiki
套用 Wiki 的描述,装饰器模式的最大特点是保留主干,增加装饰,但不影响原功能。假如用一个成语来形容,我认为最好的莫过于“锦上添花”了。
使用场景
场景1:Form表单组件,用户点击提交时把用户内容提交。增加装饰:提交之前做个校验
场景2:一个功能正常执行。增加装饰:在执行前记录下起始时间,在执行后记录下结束时间并计算消耗时间
场景3: 用户点击按钮,执行某个功能。增加装饰:在执行前发请求到统计平台,统计用户的点击次数
场景4:给一个编辑器组件增加一个输入改变时,保存数据到服务器节流的装饰
AOP 面向切面编程
Java 大名鼎鼎的 Spring 框架的核心编程思想 - AOP 面向切面编程,装饰器模式就是它比较常见的实现。
什么是设计模式?
设计模式就是代码问题的一套解决方案,或者说,解决特定问题的“最佳实践”。
常见的设计模式大概有23种,这里以一张图片说明。
本文先聊聊以下四种设计模式。
对象
JS 面向对象的改造
JS 匿名函数
组合模式(Composite Pattern)
特点:
适配器模式(Adapter Pattern)
一句话,适配器模式可以类比于家里的插座,上面有不同类型的插孔,用来适配不同的插头。
实际的开发场景
场景1
使用nodejs做一个ORM框架,给用户暴露一套统一的数据库操作接口,底层根据数据库类型适配不同数据库。
场景2
做一个日志模块,给用户暴露一套统一的记录日志接口,底层根据类型适配是文件存储日志还是数据库存储日志。
场景3
前端开发过程中需用到获取数据和保存数据。在开发阶段,可以把数据存储和查询用 localStorage 来做;接口就绪后可以发送请求从服务器存取数据。使用适配器模式,为使用者提供统一接口。
以下为适配器模式的代码示例。
装饰者模式(Decorator Pattern)
先问一个问题:如何给一个对象增加额外的功能?
方法1:直接修改对象
方法2:创建子类继承自父类,子类实例化新对象(如果太细,会导致子类对象的泛滥)
方法3:不改变原对象,在原对象基础上进行“装饰”,新增一些和核心功能无关的功能
装饰器模式即为上述方法3。
套用 Wiki 的描述,装饰器模式的最大特点是保留主干,增加装饰,但不影响原功能。假如用一个成语来形容,我认为最好的莫过于“锦上添花”了。
使用场景
场景1:Form表单组件,用户点击提交时把用户内容提交。增加装饰:提交之前做个校验
场景2:一个功能正常执行。增加装饰:在执行前记录下起始时间,在执行后记录下结束时间并计算消耗时间
场景3: 用户点击按钮,执行某个功能。增加装饰:在执行前发请求到统计平台,统计用户的点击次数
场景4:给一个编辑器组件增加一个输入改变时,保存数据到服务器节流的装饰
AOP 面向切面编程
Java 大名鼎鼎的 Spring 框架的核心编程思想 - AOP 面向切面编程,装饰器模式就是它比较常见的实现。
下面用 JS 来实现一个简单的 AOP 对象。
ES7 Decorator 修饰符
借鉴其他语言的优势,JS 在 ES7 推出了 Decorator 修饰符,不好理解也不太实用,但如果熟悉装饰器模式的话,理解起来就容易多了:这不就是装饰器模式的语法糖嘛,示例如下。
使用 Decorator 修饰符,修改原型属性
Tips: 运行代码需babel支持,把JavaScript模式调整到ES6/babel
总结
设计模式看起来似乎有些枯燥乏味,学习起来短期可能也并不能见到效果,但当业务变得复杂、代码变得越来越冗余时,设计模式就能给你正确的指引。毕竟代码相关的“最佳实践”流传至今,必定有它存在的道理。