[JavaScript] closures

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。
    • JS对变量的declare, define, scope很自由,var可以不声明就使用,考虑到有需要将变量在fn中private,就可以通过闭包的方式实现
    • 闭包是一个函数的局部变量 - 函数返回后它还活着
    • 闭包是一个函数返回时但是内存堆栈帧不会被释放,不会被垃圾回收。

性能考量

<span style="font-family: '.PingFangSC-Regular'">如果不是某些特定任务需要使用闭包,在其他函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响。</span>
  • method in prototype 👍 / constructor 👎将导致每次构造器被调用时,方法都会被重新赋值一次

实用闭包

// (fn)() 这种写法,(fn)是声明一个匿名的fn对象,()是自执行,返回一个实例,id就成了fn对象实例的属性了,且闭包
// 注意区分声明和实例化,就能很好理解闭包了
_uniqueID = (function(){
var id = 0;
/*
* 返回的匿名fn中,持有id的引用,所以在自执行之后,变量id不会被GC,这是闭包的本质;
*/
return function () {return id ++}
})();

alert(_uniqueID()); //0
alert(_uniqueID()); //1

// 变量的scope
var a = 1;
var b = 2;
(function() {
var b = 3;
a += b;
})();
console.log(a); //4
console.log(b); //2

内存泄漏

闭包会在不经意间导致内存的泄漏(主要是ie,ie自有GC); IE 中,每当在一个 JavaScript 对象和一个DOM对象之间形成循环引用时,就会发生内存泄露。
// Common Example
function leakMemory() {
var el = document.getElementById('el');
var o = { 'el': el };
el.o = o;
}
// Closure Example
function addHandler() {
var el = document.getElementById('el');
el.onclick = function() {
el.style.backgroundColor = 'red';
}
}
// Resolve 1
function addHandler(){
document.getElementById('el').onclick = function(){
this.style.backgroundColor = 'red';
};
}
// Resolve 2
function addHandler() {
var clickHandler = function() {
this.style.backgroundColor = 'red';
};
(function() {
var el = document.getElementById('el');
el.onclick = clickHandler;
})();
}

在循环中创建闭包:一个常见错误

参考[1]
<p id="help">Helpful notes will appear here</p>
<p>E-mail: <input type="text" id="email" name="email" /></p>
<p>Name: <input type="text" id="name" name="name" /></p>
<p>Age: <input type="text" id="age" name="age" /></p>

function showHelp(help) {
document.getElementById("help").innerHTML = help;
}

function setupHelp() {
var helpText = [
{ id: "email", help: "Your e-mail address" },
{ id: "name", help: "Your full name" },
{ id: "age", help: "Your age (you must be over 16)" },
];

for (var i = 0; i < helpText.length; i++) {
var item = helpText[i]; // 这里发生了变量提升,导致执行完之后,item 指向最后一个元素
document.getElementById(item.id).onfocus = function () {
showHelp(item.help);
};
}
}

setupHelp();


Date:
Words:
810
Time to read:
4 mins