1. 回调示例
如果有个模块 findeNodes()
,任务是找到期望的 DOM 元素并使用 hide()
处理:
function findNodes() {
var i = 10000, nodes = [], found
while (i--) {
// ...复杂逻辑,筛选出符合的元素 found
nodes.push(found)
}
return nodes
}
function hide(nodes) {
for (let i = 0, max = nodes.length; i < max; i++) {
nodes[i].style.display = 'none'
}
}
hide(findNodes())
2. 改进
可以看到函数 findNodes()
和 hide()
分别两次进行了循环,这是十分低效的,如果要避免这种重复循环,并且只要在 findNodes()
中选择的时候就进行 hide()
那么将是高效的实现方式。如果在 findNodes()
中实现修改逻辑,由于检索和修改逻辑耦合,那么它将不再是一个通用函数。对这种问题的解决方法是采用回调模式。
可以将节点隐藏逻辑以回调函数的方式传递给 findNodes()
并委托执行:
function findNodes(callback) {
var i = 10000, nodes = [], found
if (typeof callback !== 'function') { // 检查参数是否为可调用
callback = false
}
while (i--) {
// ...复杂逻辑,筛选出符合的元素 found
if (callback) {
callback(found)
}
nodes.push(found)
}
return nodes
}
function hide(nodes) {
nodes[i].style.display = 'none'
}
findNodes(hide)
那么现在回调函数可选,重构后加入回调函数参数的 findNodes()
仍然可以像以前一样使用,而不会破坏旧 API 的原始代码。
3. 回调与作用域
前面的例子中,回调执行的语句:callback(para)
,在多数情况下有效,但是如果传递的函数是对象的方法且有 this
那么回调方法里的 this
将指向的是全局对象,从而发生意外。
解决这个问题的方法是传递回调函数,并且还传递该回调函数所属的对象:
function findNodes (callback, callback_obj){
...
if (typeof callback === 'function'){
callback.call(callback_obj, found)
}
...
}
findNodes (obj.sayName, obj)
当然,可以把方法作为字符串来传递,避免重复两次输入该对象的名称:
findNodes (callback, callback_obj){
if (typeof callback === 'string'){
callback = callback_obj[callback]
}
if (typeof callback === 'function'){
callback.call(callback_obj, found)
}
}
findNodes('sayName', Obj)
本文是系列文章,可以相互参考印证,共同进步~
网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出~
参考:<JavaScript 模式> P65
PS:欢迎大家关注我的公众号【前端下午茶】,一起加油吧~
另外可以加入「前端下午茶交流群」微信群,长按识别下面二维码即可加我好友,备注加群,我拉你入群~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。