美文网首页
一次性理解立即执行函数和闭包

一次性理解立即执行函数和闭包

作者: 不讨喜的大雄 | 来源:发表于2018-08-18 16:18 被阅读0次

Immediately-Invoked Function Expression(IIFE):立即调用函数表达式

使用全局变量可能会造成一些不必要的麻烦
因此我们要使用局部变量

在 java 语言中我们可以用 { } 将代码包裹起来,使它们成为局部变量
但是这在 ES5 中不行,因为 var 有变量提升

{
  var a = 1;
}
// 上面代码等同于
var a 
{
  a = 1;
}

ES6 里面引入了 let 的概念,于是有了块级作用域
解决了这个问题,IIFE 似乎就变得不那么必要了

{
  let a = 1;
}
a 
// Uncaught ReferenceError: a is not defined

但是了解 IIFE 可以让我们初学者更好得理解函数表达式、变量提升等的概念,以及了解前端语言的发展进程,知道前人一步步将原本不那么美好的 js 变得规范化的过程,学习他们的智慧。

ES5 里面,没有块级作用域,只有函数(函数作用域)可提供局部变量环境
于是我们声明一个 function xxx,然后 xxx.call()

function xxx(){
  var a = 1;
}.call()

但是这个时候 xxx 也是全局变量(全局函数)
所以我们不能给这个函数名字,即需要使用匿名函数

function(){
  var a = 1;
}.call()
// Uncaught SyntaxError: Unexpected token (

但是这在 Chrome 里会报错,js 语法错误

这是由于浏览器认为这是一个函数声明
解决办法:让浏览器去解析这个函数表达式

如给函数取反

! function(){
  var a = 1;
}.call() 
// 我们不在乎这个匿名函数的返回值,所以加个 ! 取反没关系

类似的还有

+function(){}()
-function(){}()
~function(){}()
void function(){}()
new function(){}()
// function(){}() === function(){}.call()
//用 .call() 更清楚

如果实在不想改变函数返回值,也可以用圆括号

(function(){}).call() 
(function(){}.call())

但是方法会有不好的情况:如果括号前面有东西

a
(function(){}).call() 
//等价于
a().call() 
//这不是我们想要的
//同理
a
(function(){}.call())
//等价于
a()

所以不推荐

你也可以用一个随机变量名函数而不用匿名函数,永远都不会变量污染的那种变量(这种方法好吗?)

function ada231231284u3lkda(){
  var a = 1;
}.call()

当然最推荐的还是用取反 !,这就好像是个警示:我要开始用 IIFE 了


IIFE 达到了局部变量的效果,外面访问不到立即执行函数里面的变量(避免变量污染)

但有时候我们需要访问 IIFE 里面的内容,怎么办?
最简单的方法是直接用全局变量 window

! function(){
  var a = window.a = {
    n: 1
  }
}.call() 
// 另一个立即执行函数通过 window.a 访问
! function(){
  var b = window.a
  console.log(a)
}.call() // {n: 1}

我们还可以在 IIFE 里面使用闭包来隐藏 a

! function(){
  var a = {
    n: 1
  }
  // 声明一个匿名函数保存于 window.nAdd1 
  window.nAdd1 = function(){
    a.n += 1
    // return 新的 a.n
    return a.n
  }
}.call() 
// 匿名函数可以操作函数外面的变量 a ,这就是闭包
// 另一个立即执行函数通过 window 访问
! function(){
  var b = window.nAdd1()
  console.log(newN)
}.call() // 2

IIFE 使得 a 成为局部变量而无法被外部访问
闭包使得匿名函数可以操作 a
window.nAdd1 保存了匿名函数的地址
任何地方都可以使用 window.nAdd1
=> 任何地方都可以使用 window.nAdd1 操作 a,但是不能直接访问 a
这就是 window 和闭包联合作用的效果

闭包

将上面代码整合在一起,就是闭包的常见形式

function fn(){
  var a = {
    n: 1
  }
  function fn2(){
    a.n += 1
    return a.n
  }
  return fn2
}
var fn1 = fn()
fn1() // 2
// 上面代码其实就是
(function(){
  var a = {
    n: 1
  }
  return function(){
    a.n += 1
    return a.n
  }
}.call()) // IIFE
.call()// 2

现在我们明白了为什么闭包一般在 IIFE 里出现
IIFE 提供局部变量的环境,才有闭包的用武之地
return 的作用
上面代码中的 return 和 window 的作用一样,是为了让外部能够访问函数作用域内部的函数,当然 return a.n 的作用也是如此

而闭包的作用,至此应该理解了


本文仅作为个人学习使用

相关参考:
Immediately-Invoked Function Expression (IIFE)
「每日一题」什么是立即执行函数?有什么作用?
「每日一题」JS 中的闭包是什么?
JS标准参考教程——IIFE
ES6入门——let#块级作用域

相关文章

  • 理解立即执行函数和闭包

    立即执行函数 写代码时尽量不要使用全局变量,因为很可能会相互覆盖 在 java 语言中我们可以用 { } 将代码包...

  • es5核心技术

    立即执行函数 函数提升和变量提升 闭包 this 原型链实现继承

  • 一次性理解立即执行函数和闭包

    Immediately-Invoked Function Expression(IIFE):立即调用函数表达式 使...

  • 立即执行函数和闭包

    立即执行函数: 一、计时器 一次性定时器 setTimeOut(function(){ //1秒后执行 },100...

  • 闭包和立即执行函数

    闭包:先来看一个题目:实现一个函数,每次调用自增1 你有可能会想用全局变量,计数的时候将它加一,但是全局变量有风险...

  • 闭包和立即执行函数

    闭包闭包:内部的函数引用了外部的函数的变量,则产生闭包。闭包的作用:把变量封装在函数中,只有内部函数可以用,让函数...

  • 理解闭包

    什么是「闭包」。 「闭包」的作用是什么。在一个立即执行函数当中: 首先,假设以上几行代码运行在立即执行函数当中,那...

  • javascript立即执行函数和闭包

    闭包 概念:当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链举例分析: 闭包的应用: 立即执行函数 ...

  • 简单理解闭包与立即执行函数

    闭包 闭包 是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。——...

  • 闭包、立即执行函数闭包、BOM

    题目1: 下面的代码输出多少?修改代码让 fnArr[i]()输出i。使用 两种以上的方法 改写1 改写2 题目2...

网友评论

      本文标题:一次性理解立即执行函数和闭包

      本文链接:https://www.haomeiwen.com/subject/aulebftx.html