2020-11-09第4,5章 提升&闭包

第4章 提升

  • var a = 2 引擎会将这条语句分为 var aa = 2,一个是声明变量,编译阶段的任务,而第二个是赋值,执行阶段的任务。
  • 提升是指无论作用域中的声明出现在什么地方,都会在编译阶段放到最前面首先进行处理。这个过程将变量和函数移动到给自的作用域最顶端,这个过程被称为”提升“
  • 函数声明首先被提升,然后才是变量
  • 函数表达式中的变量声明会被提升,但是赋值操作不会。
  • 这段代码输出的是b,因为函数声明被提升了,并且被覆盖了
foo(); // "b" 
var a = true; 
if (a) { 
  function foo() { console.log("a"); } 
} 
else { 
  function foo() { console.log("b"); } 
}

第5章 作用域闭包

闭包是前端很重要的概念,但是很少有人能分辨清楚什么是闭包,并且如何去使用闭包。很多人认为函数里嵌套函数就是闭包,我认为是不对的。这本书里很好的帮我理清楚了闭包到底是什么。

  • 当函数可以记住并访问所在的词法作用域时,就产生了闭包。即使函数是在当前词法作用域之外执行的。
function foo() { 
    var a = 2; 
    function bar() { 
        console.log( a ); // 2 
    }
    bar(); 
}
foo(); 

按照上面的定义,这是闭包吗?从技术上来说,函数bar具有一个涵盖foo作用域的闭包,但是我们无法从上面代码看得出闭包如何工作的。看下面这段代码:

function foo() { 
    var a = 2; 
    function bar() { 
        console.log( a ); 
    } 
    return bar; 
} 
var baz = foo(); 
baz(); // 2 —— 朋友,这就是闭包的效果。

Baz返回的是bar函数,bar() 显然是调用的地方是在自己定义的词法作用域以外的地方执行。一般情况,foo执行结束后,通常会期待foo()的整个内部作用域都会被销毁,但是因为闭包的作用,bar()所声明的地方位置的隐私,它拥有foo的内部作用域的闭包,所以不会不销毁。bar的这个引用就叫做闭包。

  • 无论何种方式的函数值传递,我们都可以看见闭包的作用
function foo() { 
    var a = 2; 
    function baz() { 
        console.log( a ); // 2 
    }
    bar( baz ); 
} 
function bar(fn) { 
    fn(); // 妈妈快看呀,这就是闭包! 
}
var fn; 
function foo() { 
    var a = 2; 
    function baz() { 
        console.log( a ); 
    }
    fn = baz; // 将 baz 分配给全局变量 
} 
function bar() { 
    fn(); // 妈妈快看呀,这就是闭包! 
}
foo(); 
bar(); // 2
  • setTimeout, 事件监听器,ajax请求,跨窗口通信,异步任务等,只要用到了回调函数,实际上就是在使用闭包。

循环和闭包

  • 观察这段代码,执行结果:回调函数会在循环结束后执行,因为每次循环都会赋值上一次运行的值,继续运行。
for (var i=1; i<=5; i++) { 
    setTimeout( function timer() { 
        console.log( i ); 
    }, i*1000 ); 
} 
  • 对比和上面代码区别
for (var i=1; i<=5; i++) { 
    (function() { 
        setTimeout( function timer() { 
            console.log( i ); 
        }, i*1000 ); 
    })(); 
}

IIFE 会通过声明并立即执行一个函数来创建作用域,虽然有了独立的作用域但是什么都没有,需要一个变量存储变量才行

for (var i=1; i<=5; i++) { 
    (function() { 
        var j = i; 
        setTimeout( function timer() { 
            console.log( j ); 
        }, j*1000 ); 
    })(); 
}

//改进后

for (var i=1; i<=5; i++) { 
    (function(j) { 
        setTimeout( function timer() { 
            console.log( j ); 
        }, j*1000 ); 
    })( i ); 
}

这里才是预期的效果,一段时间后输出循环的参数。

小结: 这部分还需要再多看几遍,有一种似懂非懂的感觉,还不能十分把握说清楚。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容