这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战」。
闭包可以读取函数内部的变量,并让这些变量始终保存在内存中;
立即调用的函数表达式 (IIFE)
立即调用的函数表达式 (IIFE,Immediately Invoked Function Expression): 顾名思义,就是在创建函数后立即调用的函数。
1. 写法
函数被包裹在括号里,被当做函数表达式,后面再紧跟一组括号会立即调用它前面的函数表达式。
// 第一种写法
(function(){
console.log('巴拉巴拉')
})(); // 巴拉巴拉
// 第二种写法
(function(){
console.log('巴拉巴拉')
}()); // 巴拉巴拉
2. 应用
- IIFE模拟块级作用域, es6之前很常用的一种方式
// es6 let
for(let i =0; i < 5; i++){
console.log(i)
}
防止变量定义外泄, 也不会导致闭包相关的内存问题,因为不存在对这个匿名函数的引用。只要函数执行完毕, 其作用域链就可以被销毁。
惰性函数
函数内部的判断只会执行一次,后序再执行都不会再做判断逻辑。他的原理是使用了闭包,在内部做完条件判断后,返回了一个新的函数出来,等于是当前函数已经被改写了。
const addEvent = (function () {
if (window.addEventListener) {
return (elem, type, fn, capture) => {
elem.addEventListener(type, (e) => fn.call(elem, e), capture);
};
} else {
return (elem, type, fn, capture) => {
elem.attachEvent('on' + type, (e) => fn.call(elem, e);
};
}
})();
缓存数据
空间换时间。就是在多次调用计算方法的时候,其实有的值之前可能已经计算过了,我们可以利用闭包将计算结果存在函数内,计算之前先判断缓存内是否有,没有的话就再计算,更新缓存。
function fnL() {
var only = 'onlyfnL';
return function fn2(ang=only){
var name = 'namefn2';
only = ang;
console.log(only,name)
}
}
let act1 = fnL();
let act2 = fnL();
单例模式
单例模式是设计模式的一种,一个类只有一个实例,在创建实例的时候会先判断是否已经有实例,如果有则直接返回,没有的话才创建,优点就是避免重复创建实例,减少内存开销。
// 单例模式
function Singleton(){
this.data = 'singleton';
}
Singleton.getInstance = (function () {
var instance;
return function(){
if (instance) {
return instance;
} else {
instance = new Singleton();
return instance;
}
}
})();
var sa = Singleton.getInstance();
var sb = Singleton.getInstance();
console.log(sa === sb); // true
console.log(sa.data); // 'singleton'
私有变量
保存自己私有变量,通过提供接口给外部使用,但外部不能直接访问该变量。
// 模拟私有属性
function getGeneratorFunc () {
var _name = 'John';
var _age = 22;
return function () {
return {
getName: function () {return _name;},
getAge: function() {return _age;}
};
};
}
var obj = getGeneratorFunc()();
obj.getName(); // John
obj.getAge(); // 22
obj._age; // undefined
compose函数
容易和柯里化函数搞混,compose是将多个回调调用的函数整合成一个接受多个函数为参数的函数,即F(A(B(x)))=>P(F,A,B)(x)
compose函数可以让整个js代码可读性更强。他的原理其实也是用到了闭包,实现如下
var compose = function(...args) {
var len = args.length
var count = len - 1
var result
return function f1(...args1) {
result = args[count].apply(this, args1)
if (count <= 0) {
count = len - 1
return result
} else {
count--
return f1.call(null, result)
}
}
}
科里化
维基百科中定义:科里化(英文:Currying): 又译为卡瑞化或加里化;
是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
柯里化的优点有:
- 参数的复用,如果多次调用一个函数,传入的参数大部分都是相同的,可以考虑用柯里化函数,将前面相同参数的部分封装起来,再去接受后面不同的参数,减少函数的调用。
- 延迟计算,分段传入参数调用函数,等真正需要返回结果的时候,不传参数直接调用。
function currying(fn, args) {
var _this = this
var len = fn.length
var args = args || []
return function() {
var _args = Array.prototype.slice.call(arguments)
Array.prototype.push.apply(args, _args)
if(_args.length < len) {
return currying.call(this, fn, _args)
}
return fn.apply(this, _args)
}
}
函数柯里化的作用是能够使得参数复用和函数的延迟执行
偏应用函数
偏函数是指使用一个函数并将其应用一个或多个参数,但不是全部参数;他会创建一个接收剩余参数的函数
function info(country) {
return function (province, city) {
console.log(country + "-" + province + "-" + city);
};
}
let place = info("中国")
place(); //中国-undefined-undefined
place("山东省", "济南市"); // 中国-浙江省-杭州市