小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前言
函数有很多概念,其中有一个很重要而且必学掌握的概念,那就是闭包,今天我们一起来学习吧。
定义
下面文字来自《Javascript权威指南 第六版》
函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的。
函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中称为“闭包。
闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。
function sum(a){
return function (b){
return a + b;
}
}
const sum1 = sum(10);
const result = sum1(20); // 30
a就是另外一个函数的变量。
因为闭包会保留它们包含函数的作用域,所以比其他函数更占用内存。过度使用闭包可能导致内存过度占用,因此建议仅在十分必要时使用。V8等优化的JavaScript引擎会努力回收被闭包困住的内存,不过我们还是建议在使用闭包时要谨慎。
var utils = (function (global) {
function getQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]);
return null;
}
function getType(obj){
return typeof obj;
}
return {
get now() {
return Date.now()
},
getQueryString,
getType
}
})(window)
上面utils不被释放,其内部的函数getQueryString,getType,now都不会被释放的。
想释放怎么办?
utils = null;
this
在闭包中使用this会让代码变复杂。如果内部函数没有使用箭头函数定义,则this对象会在运行时绑定到执行函数的上下文。
var name = "Tom";
var createPerson = function (name){
return {
name,
getName(){
return this.name;
},
getName2: ()=> {
return this.name
}
}
}
var person = createPerson("Henry");
person.getName(); // Henry
person.getName2(); // Tom
科里化和偏函数
科里化和偏函数是闭包的一种典型应用。
function currying(fn){
var allArgs = [];
return function next(){
var args = [].slice.call(arguments);
if(args.length > 0){
allArgs = allArgs.concat(args);
return next;
}else{
return fn.apply(null, allArgs);
}
}
}
是不是一种浓浓的闭包信息呢?
闭包创建私有变量
利用闭包可以创建私有变量,当然现在的class已经有#私有变量符号,不过真心的丑,还不然TypeScript的私有变量好看好用。
function Person() {
var name, age;
function getName() {
return name;
}
function setName(val) {
name = val;
}
function getAge() {
return age
}
function setAge(val) {
age = val;
}
return {
getName,
setName,
getAge,
setAge
}
}
var person = new Person();
person.setAge(10);
person.setName("Tom");
console.log(person.getName(), person.getAge());
// Tom 10
经典案例
for (var i = 0; i < 5; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
// 5 5 5 5 5
在没有let, const块作用域的时候,怎么解决这个问题呢? 其中一种答案就是IIFE,立即执行函数表达式, 下篇继续。
小结
今天你收获了吗?