JavaScript的语言特性 — 闭包

前端技术 everyinch 1087℃ 0评论

闭包(closure)意味着内层的函数可以引用存在于包围它的函数内的变量,即使外围函数的执行已经终止。

// 查找 id 为 'main' 的元素
var obj = document.getElementById("main");

// 修改它的 border 样式
obj.style.border = "1px solid red";

// 初始化一个在一秒后执行的回调函数(callback)
setTimeout(function(){
    // 它将隐藏此对象
    obj.style.display = 'none';
}, 1000);

// 一个用于延时显示警告信息的通用函数
function delayedAlert( msg, time ) {
    // 初始化一个封装的回调函数
    setTimeout(function(){
        // 它将使用包含本函数的外围函数传入的 msg 变量
        alert( msg );
    }, time );
}

// 用两个参数调用 delayedAlert 函数
delayedAlert( "Welcome!", 2000 );

上面的例子演示了如何利用闭包避免糟糕的代码。displayAlert函数在函数作用域内使用了闭包,解决代码混乱的问题。

在一些函数式程序设计语言中,有一种称为Curry化(currying)的技术。本质上,Curry化是一种通过把多个参数填充到函数体中,实现将函数转换为一个新的经过简化的函数的技术。下面的代码通过向辽宁国外一个函数预填参数而创建了一个新函数。

// 数字求和函数的函数生成器
function addGenerator( num ) {

    // 返回一个简单的函数,求两个数字的和
	// 其中第一个数字来自生成器
    return function( toAdd ) {
        return num + toAdd
    };

}

// addFive 现在包含一个接受单一参数的函数
// 这个函数能求得 5 加上该参数的和
var addFive = addGenerator( 5 );

// 在传入参数 4 时,addFive 函数的结果是 9
alert( addFive( 4 ) == 9 );

闭包还能解决另一个常见的JavaScript编写问题:开发新手经常会声明大量的全局变量,这些变量可能会影响其它的库,从而导致一些问题。通过自执行的匿名函数可以把所有原本属于全局的变量都隐藏起来。

// 创建一个新的匿名函数,作为包装
(function(){
    // 变量原本是全局的
    var msg = "Thanks for visiting!";

    // 将一个新函数绑定到全局对象
    window.onunload = function(){
        // 这个函数使用了隐藏的 msg 变量
        alert( msg );
    };

// 关闭匿名函数并执行之
}());

最后,让我们看看使用闭包会遇到的一个问题。闭包允许引用父函数中的变量,但提供的值并非该循环变量创建时的值,而是在父函数范围内的最终值。这样带来的最常见的问题是在for循环中,有一个变量作为循环技术(如变量i),在这个循环里创建了新的函数,利用闭包来引用循环的计数器。问题是,在这个新的闭包函数被调用时,它引用的计数器的值是其最后一次的赋值,而不是期望的那个值。

// 一个 id 为 main 的元素
var obj = document.getElementById(“main”);

// 用于绑定的一个数组
var items = [ “click”, “keypress” ];

// 遍历数组的每个元素
for ( var i = 0; i < items.length; i++ ) { // 使用一个自执行的匿名函数来激发出作用域 (function(){ // 将一个函数绑定到该元素 obj[ "on" + items[i] ] = function() { // item[i] 引用本 for 循环上下文所属作用域中的一个父变量 alert( "Thanks for your " + items[i] ); }; })(); } [/code] js7



转载请注明:陈童的博客 » JavaScript的语言特性 — 闭包

喜欢 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

无觅相关文章插件,快速提升流量