前言
IIFE
就是自调用函数
,框架和一些库中往往使用它们来提升性能
,本文简单通过几个小案例尝试理解IIFE
带来的提升。
案例1
下面这个函数,根据浏览器兼容性为某元素注册事件。
function addEvent(ele, eventName, handler) {
if (ele.addEventListner) {
ele.addEventListner(eventName, handler)
} else if (ele.attachEvent) {
ele.attachEvent("on" + eventName, handler)
} else {
ele["on" + eventName] = handler
}
}
该函数在每次被调用时都会依次进入判断,这是没必要的,因为一上来
就可以根据浏览器确定用户需要怎么处理。
将该函数修改为立即执行函数,并return不同的处理函数即可:
var addEvent = (function (ele, eventName, handler) {
if (ele.addEventListner) {
return function (ele, eventName, handler) {
ele.addEventListner(eventName, handler)
}
} else if (ele.attachEvent) {
return function (ele, eventName, handler) {
ele.attachEvent("on" + eventName, handler)
}
} else {
return function (ele, eventName, handler) {
ele["on" + eventName] = handler
}
}
})()
这也是很多框架和库的做法。
案例2
封装一个request函数,要求能同时在浏览器和node环境下运行。
const request = () => {
if (typeof window !== "undefined") {
// 浏览器环境下的ajax
} else {
// node环境下的http
}
}
情况同案例1,运行环境一上来就可以确定,所以无需每次调用时重复判断,修改方式也同案例1,改为自调用函数
,修改后代码如下:
const request = (() => {
if (typeof window !== "undefined") {
return (options) => {
// 浏览器环境下的ajax
}
} else {
return (options) => {
// node的http
}
}
})()
案例3
下面是一个函数,使用正则清除字符串中的空字符。
function removeSpace(str) {
return str.replace(/\s/g, "")
}
看上去已经很简洁了,似乎也并不会造成性能上的浪费,但其实暗藏玄机。
每次调用该函数时,都会创建一个正则对象
,而正则对象中还有一个很不起眼的""
,这个空字符串仍然会占用内存空间。如果调用该函数的场景多了,那么内存会迎来波动
,即函数执行时内存上升
,到达垃圾回收
机制的某个结点时迎来释放
。
通过IIFE
修改函数:
const removeSpace = (
() => {
const reg = /\s/g,
replacement = ""
return str => str.replace(reg, replacement)
}
)()
此时多处调用该函数,内存趋于平稳
,因为通过闭包
,变量全会局且长久的存在于内存中。
那么如何继续优化,即不会造成内存波动
而且也能忽视闭包带来的内存泄漏
呢,可以使用高阶函数
,react中也是这么处理的。
const createRemoveSpace = () => {
const reg = /\s/g,
replacement = ""
return str => str.replace(reg, replacement)
}
const removeSpace = createRemoveSpace()
console.log(removeSpace("hello world"));
console.log(removeSpace("hello world "));
console.log(removeSpace(" hello world "));
removeSpace = null; // 不再需要使用时设为null,垃圾回收机制会自动清理
上面的实现方式,在变量仍需使用时,既可以确保利用闭包的特性阻止内存的波动
,又能在调用完毕后及时进行垃圾回收
。
注意:当不再需要使用时需要手动设为null
,但在框架开发中则不需要,因为变量会随着组件的销毁而销毁
。