闭包,声明函数和表达式函数

263 阅读3分钟

闭包

定义

闭包是在一个作用域内创建一个封闭的词法环境,它通常会自动返回回来生成这个语法环境,这个环境由创建闭包时在作用域内的任何局部变量构成

作用

正常函数执行后,里面生成的变量会被垃圾回收处理掉,但是闭包可以让作用域内的变量在函数执行完后,依然没有被垃圾回收处理掉

实例

  • 计时器
function add() {
    var count = 0;
    return function () {
        count++;
        console.log(count);
    };
}

let countAdd = add();

countAdd(); //1
countAdd(); //2

在调用countAdd的时候,会返回一个函数,函数是可以创建自己的作用域的,但是count函数引用了add函数下的count参数,所以这个参数是不可以被销毁的。

所以接下来我们需要几个计数器,就创建几个函数就可以了,他们之间是相互不影响的

var fun1 = addCount();
fun1(); //1
fun1(); //2
var fun2 = addCount();
fun2(); //1
fun2(); //2

声明函数和表达式函数

// 声明函数
function hello() {
  return "HELLO"
}    
// 表达式函数  
var h1 = function hello() {
  return "HELLO"
}    

声明提前

首先说一下变量声明提前

变量声明语句会被提前到函数/脚本的顶部,但是赋值的操作还在原来的位置执行,在赋值语句之前,变量的值为undefined 即

  1. 变量声明会提前到函数的顶部;
  2. 只是声明被提前,初始化不提前,初始化还在原来初始化的位置进行初始化;
  3. 在声明之前变量的值是undefined。

函数声明提前

funDeclaration("Declaration");//=> true
function funDeclaration(type){
    return type==="Declaration";
}
funExpression("Expression");//=>error
var funExpression = function(type){
   return type==="Expression";
}

由上面例子可知:使用声明函数定义的函数时,函数调用可以放在任何位置

函数声明提前的时候,函数声明和函数体都提前了

函数声明是在预执行期执行的,就是说函数声明是在浏览器准备执行代码的时候执行的。因为函数声明在预执行期被执行,所以到了执行期,函数声明就不再执行(人家都执行过了自然就不再执行了)。

为什么表达式函数不能提前声明

上面对于var的声明提前,只是声明提前了,初始化没有提前,初始化还在原来的地方初始化

表达式函数就是把一个函数对象赋值给变量了,所以对于表达式函数来说赋值是不会提前的

实例分析

sayTruth();
if(1){
    function sayTruth(){alert('myvin is handsome')};
}
else{
    function sayTruth(){alert('myvin is ugly')};
}
//myvin is ugly

因为函数声明提前,所以函数声明会在代码执行前进行解析,执行顺序是这样的,先解析function sayTruth(){alert('myvin is handsome')},在解析function sayTruth(){alert('myvin is ugly')},覆盖了前面的函数声明,当我们调用sayTruth()函数的时候,也就是到了代码执行期间,声明会被忽略,所以自然会输出myvin is ugly

函数声明是在预执行期执行的,就是说函数声明是在浏览器准备执行代码的时候执行的。因为函数声明在预执行期被执行,所以到了执行期,函数声明就不再执行了(人家都执行过了自然就不再执行了)