1、提升
函数声明提升的优先度比变量提升的优先度要高
函数表达式不会提升
2、闭包
2.1 简介
函数内声明函数可以说是闭包,但准确的来说并不是。
闭包:某函数在声明的作用域外被调用并且能够阻止「原作用域」的销毁,以及使用原作用域内的变量
闭包和块作用域结合是最屌的
var result = [];
var a = 3;
var total = 0;
function foo(a) {
//3.这里如果被改为let i 将会是绝杀,可惜改不得,因为let会在每一次的迭代里面生成一个封闭的作用域
for (var i = 0; i < 3; i++) {
result[i] = function () { //2.因为这里的闭包都有一个共享的作用域,i就在那个被共享的作用域里
total += i * a; //1.这里还没有调用,所以不用急着赋值,只是指定了result 的每一项是一个函数,函数有这个功能
console.log(total);
}
}
}
foo(1);
//2.这里才调用闭包函数 此时foo函数里的for循环已经执行完毕,i已经被定为3
result[0](); // 3
result[1](); // 6
result[2](); // 9
2.2 闭包的作用
闭包可以阻止作用域被销毁
也可以把一些函数内的值保存下来。闭包可以实现方法和属性的私有化,比如生成一个模块,看书p56
2.3 闭包经典使用场景
2.3.1 return 回一个函数
function foo() {
var a = 2;
function bar() {
console.log(a);
}
return bar;
}
var baz = foo();
baz(); // 2
2.3.2 IIFE(自执行函数)
this指向全局作用域
(function (a) {
console.log(a);
})(1)
2.3.3 循环赋值
settimeout里的回调函数的this指向全局作用域
for(var i = 0; i<10; i++){
(function(j){
setTimeout(function(){
console.log(j)
}, 1000)
})(i)
}
因为存在闭包的原因上面能依次输出1~10,闭包形成了10个互不干扰的私有作用域。将外层的自执行函数去掉后就不存在外部作用域的引用了,输出的结果就是连续的 10。为什么会连续输出10,因为 JS 是单线程的遇到异步的代码不会先执行(会入栈),等到同步的代码执行完 i++ 到 10时,异步代码才开始执行此时的 i=10 输出的都是 10。
2.3.4 回调函数
setTimeout(function(){
console.log(j)
}, 1000)
…见参考文章