Fork me on GitHub

立即执行函数(function(){})()与闭包

变量的作用域

var变量

一、在js中,变量的定义并不是以代码块作为作用域的,而是以函数作为作用域。也就是说,如果变量是在某个函数中定义的,那么,它在函数以外的地方是不可见的。但是,如果该变量是定义在if或者for这样的代码块中,它在代码块之外是可见的。

二、在js中,术语“全局变量”指的是定义在所有函数之外的变量(也就是定义在全局代码中的变量),与之相对的是“局部变量”,所指的是在某个函数中定义的变量。其中,函数内的代码可以像访问自己的局部变量那样访问全局变量,反之则不行。

ES6规范

let

因为var变量是以函数作为作用域的,于是ES6新增了以代码块作为作用域的let声明方式。

let声明的值只能作用域本代码块(for、if等),重复声明会报错。

    for(var i=0;i<10;i++){
          let a = 'a';   //用let代码块外部就访问不到,而用var声明时for循环的代码块外部可以访问
    }

    console.log(a);

const

const声明的常量值不能被改变

//常量声明时要赋值,赋值后不能改变值
const MAX = 99;

//常量中的内容能被改变是因为这是个引用率类型,这时虽然内容变了但是地址依然是之前的地址
const a = {a:'a'};
a.a = 'b'

立即执行函数

匿名(function(){})()

//声明一个普通函数,函数的名字叫fn
function fn(){
    console.log("hello");
}
/*然后将函数的名字去掉即是匿名函数*/

//匿名函数,运行时会发现报错啦!
function (){
    console.log("hello");
}

/**单独运行一个匿名函数,由于不符合语法要求,会报错!
 *解决方法只需要给匿名函数包裹一个括号即可,匿名函数在其它应用场景中外层括号可以省略
 */
(function (){
    //由于没有执行该匿名函数,所以不会执行匿名函数体内的语句。
    console.log("hello");
})

//在匿名函数后面加上一个括号即可立即执行
(function (){
    console.log("hello");
})()

//若需要传值,直接将参数写到括号内即可
(function (str){
    console.log("hello "+str);
})("world!")

当一个匿名函数被括起来,然后再在后面加一个括号,这个匿名函数就能立即运行起来。

匿名函数的应用场景

事件
<input type="button" value="点我!" id="btn">

<script>
    //获得按钮元素
    var sub=document.querySelector("#btn");
    //给按钮增加点击事件。
    sub.onclick=function(){
        alert("当点击按钮时会执行到我哦!");
    }
</script>
对象
var obj={
    name:"Java",
    age:18,
    fn:function(){
        return "Program:"+this.name+"age:"+this.age;
    }
};

//调用
console.log(obj.fn());
函数表达式
//将匿名函数赋值给变量fn。
var fn=function(){
    return "赋给变量的匿名函数!";
}

//调用方式与调用普通函数一样
console.log(fn());
回调函数
setInterval(function(){
    console.log("这是一个回调函数,每次1秒钟会被执行一次");
},1000);
返回值
//将匿名函数作为返回值
function fn(){

    //返回匿名函数
    return function(){
        return "hello";
    }

}

//调用匿名函数
console.log(fn()());

//或用变量接收匿名函数然后用变量名调用
var box=fn();
console.log(box());

$(function(){})

$(function(){});是$(document).ready(function(){});的简写,相当于window.onload = function(){} ,虽然这段jquery代码与javascript代码在功能上可以互换,但执行的时间不一样,前者页面框架加载完成就执行,后者页面中所有内容加载完成才执行。

闭包

(function(){})()不叫闭包叫立即执行函数,所谓闭包,要拆成闭和包,闭指代不想暴露给外部的数据,包指代将数据打包出去暴露给外部;之所以这么说原因在于JS的函数作用域,函数内部的变量函数外部无法访问,这形成了闭函数外部想得到函数内部的变量,可以通过某些方法譬如通过return等语句将内部的变量暴露出去,这形成了包;因而——立即执行函数只是函数的一种调用方式,和闭包没有必然的联系;闭包是和作用域扯上关系的,而(function(){})()是函数声明完就执行,只是有时想要用到闭包那么可以用(function(){})()来构成闭包,而不是(function(){})()是闭包。闭包的本质是执行完后只返回有用的数据,包内变量完全销毁,防止全局污染

闭包本身定义比较抽象,MDN官方上解释是:A closure is the combination of a function and the lexical environment within which that function was declared.
中文解释是:闭包是一个函数和该函数被定义时的词法环境的组合。

普通函数实现闭包

按照闭包起的作用来理解它:就是能在一个函数外部执行这个函数内部定义的方法,并访问这个函数内部定义的变量。

function box(){
  var a = 10;
  function inner(){
    return a;
  }
  return inner;
}

var outer = box();  //获取函数内部的函数
console.log(outer());//并执行这个函数,返回结果10

正常情况,box执行过后,会被回收机制回收所占用的内存,包括其内部定义的局部变量。但是此时box执行过后返回一个内部的函数inner,这个inner引用了内部的变量a,inner又被外部outer给接收,回收机制检查到内部的变量被引用,就不会执行回收。

  • 这个案例中用到的闭包其实是inner和inner被定义时的词法环境,这个闭包被return出来后被外部的outer引用,因此可以在box外部执行这个inner,inner能够读取到box内部的变量a。

  • 使用这个闭包的目的是为了在box外部访问a,就是通过执行outer()。

匿名函数实现闭包

//1.把内部inner这个具名函数改为匿名函数并直接return
function box(){
  var a = 10;
  return function(){
    console.log(a) ; 
  }
}

var outer = box();
outer();//10

//2.把外部var outer = box()改成立即执行的匿名函数
var outer = (function(){
  var a=10;
  return function(){
    console.log(a);
  }
})();
//outer作为立即执行匿名函数执行结果的一个接收,这个执行结果是闭包,outer等于这个闭包。
//执行outer就相当于执行了匿名函数内部return的闭包函数
//这个闭包函数可以访问到匿名函数内部的私有变量a,所以打印出10
outer();//10

 

————————————————
参考:https://blog.csdn.net/qq_36189935/article/details/85275404
参考:https://www.jianshu.com/p/0a3150afb7ed

posted @ 2019-12-12 09:25  秋夜雨巷  阅读(2791)  评论(0编辑  收藏  举报