JavaScript中的匿名函数、立即执行函数和闭包

时间: 2020-01-15阅读: 260标签: 闭包

匿名函数是没有函数名的,不能单独使用;

立即执行函数是基于匿名函数实现的,也没有函数名,会在定义后立即执行;

闭包是有权访问另一个函数作用域中的变量的函数。匿名函数、立即执行函数只要满足 有权访问另一个函数作用域中的变量 这一个条件,就成了闭包。


匿名函数

匿名函数:没有函数名的函数

匿名函数不能单独定义与使用

function foo() {
  console.log('普通函数');
}
// 去掉函数名 foo 
function () { // SyntaxError: Function statements require a function name
  console.log('匿名函数');
}
匿名函数的应用场景
  • 用于函数表达式
  • 作为返回值
  • 用于定义对象方法
  • 作为回调函数
  • 用于立即执行函数
  • 用于DOM元素注册事件
  • 其他 ...

用于函数表达式

var sum = function (num1, num2) {
  return num1 + num2;
};
console.log(sum(2, 3)); 

作为返回值

function sum(sum1, sum2) { 

  return function() {
    return sum1 + sum2;    
  }

}
console.log(sum(2, 3));    // [Function]
console.log(sum(2, 3)());  // 5

用于定义对象方法

var obj = {
  name: 'uakora',
  age: 27,
  foo: function() {
    console.log(this.name + ' ' + this.age);
  }
};
obj.foo(); // uakora 27 

作为回调函数

setTimeout(function() {
  console.log('匿名函数作为回调函数');
}, 1000);

用于立即执行函数

(function() {
  console.log('立即执行函数是基于匿名函数创建的');
}());

用于DOM元素注册事件

<input type="button" value="Click me!" id="btn">
<script>
    var btn = document.querySelector("#btn");
    //给按钮注册点击事件
    sub.onclick = function(){
        console.log('Click event');
    }
</script>


立即执行函数

立即执行函数(IIFE,Immediately-Invoked Function Expression),是一种在定义后就会立即执行的函数,其实质是一种语法

立即执行函数的形式

两种常用形式

常用形式一:将匿名函数包裹在一个括号运算符中,后面再跟一个括号

(function () {
  console.log('立即执行函数');
})(); // !!!特别说明:若此立即执行函数后面立马又跟着一个立即执行函数,一定要在结尾加分号,否则后面的立即执行函数会报错!

// 上一个立即执行函数不加分号,下行代码将报错:TypeError: (intermediate value)(...) is not a function
(function (a, b, c) { // 形参
  console.log(a + b + c);  // 6
})(1, 2, 3); // 实参

常用形式二:匿名函数后面跟一个括号,再将整个包裹在一个括号运算符中

(function () {
  console.log('立即执行函数');
}());

(function (a, b, c) { // 形参
  console.log(a + b + c);  // 6
}(1, 2, 3)); // 实参

其他形式

可以用 !、+、-、~ 运算符代替常用形式一中的第一个括号

!function (a, b, c) { 
  console.log(a + b + c);  // 6
}(1, 2, 3);

+function (a, b, c) { 
  console.log(a + b + c);  // 6
}(1, 2, 3);

-function (a, b, c) { 
  console.log(a + b + c);  // 6
}(1, 2, 3);

~function (a, b, c) { 
  console.log(a + b + c);  // 6
}(1, 2, 3);
立即执行函数的作用

立即执行函数最本质的作用是:创建一个独立的作用域。利用这一功能,可以

  • 初始化数据和页面(只执行一次)
  • 模块化开发中,定义私有变量,防止污染全局(独立作用域)
  • 解决闭包中的状态保存问题;(常见的一个函数内部返回多个函数,调用这些函数,打印父函数内部变量的问题)

案例分析

var liList = document.getElementsByTagName('li');
for(var i = 0; i < liList.length; i++) {
  liList[i].onclick = function() {
    alert(i); // 结果:alert 出来的总是 6, 而不是0、1、2、3、4、5
  }
}

期望结果:0、1、2、3、4、5
实际结果:alert 出来的总是 6
原因分析:没有形成独立作用域,每次点击执行函数都是去访问同一个 i 值(且是循环结束后的值 6)
解决方案:使用立即执行函数为每个 li 元素的点击事件函数创建独立作用域

var liList = document.getElementsByTagName('li');
for (var i = 0; i < 6; i++) {
  (function (i) {
    liList[i].onclick = function () {
      alert(i); // 0、1、2、3、4、5
    }
  })(i);
}


闭包

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。闭包可以有函数名,也可以是匿名函数(没有函数名);

闭包形式一:直接以匿名函数的形式作为外部函数的返回值(普遍用法)

function outer() {
  var n = 1;

  return function() {
    n++; // 访问 outer 函数作用域中的变量 n,形成闭包
    console.log(n);
  }
}

outer()();

闭包形式二:在外部函数内定义一个内部函数,并返回内部函数名

function outer() {
  var n = 1;

  function inner() {
    n++; // 访问 outer 函数作用域中的变量 n,形成闭包
    console.log(n);
  }

  return inner;
}

outer()();

闭包形式三:在外部函数内定义一个立即执行函数

function outer() {
  var n = 1;

  (function() {
    n++; // 访问 outer 函数作用域中的变量 n,形成闭包
    console.log(n);
  })();

}

outer();
闭包的作用

作用一:可以直接访问函数作用域中的变量
作用二:可以将函数作用域中的变量如全局变量一样始终保存在内存中 (其实能否一直保存局部变量,跟闭包的执行形式有关

说明:作用二的解析为个人理解

以下示例为证明观点:闭包能否一直保存局部变量,跟闭包的执行形式有关

闭包执行方式一:在返回的闭包后面紧跟一个 () ,立即执行

function outer() {
  var n = 1;

  function inner() {
    n++;
    console.log(n);
  }

  return inner;
}

outer()();  // 2
outer()();  // 2  

闭包执行方式二:将返回的闭包赋值给一个全局变量,全局变量运行 () 操作,执行闭包

function outer() {
  var n = 1;

  function inner() {
    n++;
    console.log(n);
  }

  return inner;
}

var inner = outer();
inner();    // 2
inner();    // 3  (是在 2 的基础上加 1)

以上两种执行方式单独使用,只能说明 第二种执行方式,能使闭包一直保存局部变量,但还不能证明闭包的第一种执行方式不能一直保存局部变量,因为每次执行 outer()函数时,变量 n 都被重新初始化了。

请继续看以下代码,同时使用了闭包的两种执行方式:

function outer() {
  var n = 1;

  function inner() {
    n++;
    console.log(n);
  }

  return inner;
}

var inner = outer();

outer()();  // 2
outer()();  // 2  (Flag1)

inner();    // 2  (Flag2)
inner();    // 3

可以看到,Flag1 跟 Flag2 的值都是 2,假设 outer()() 这样的闭包执行方式会一直保存局部变量在内存的话,那 Flag2 处的值应该是 3。

显然假设不成立。

从而说明:闭包并非就一定可以一直保存局部变量在内存,还跟执行方式有关

主动释放内存
function outer() {
  var n = 1;

  function inner() {
    n++;
    console.log('n = ', n);
  }

  return inner;
}

var inner = outer();
inner();    // 2  
inner();    // 3

inner = null;  // 解除对闭包的引用,以便释放内存
闭包的应用场景
  • 保护函数局部变量的安全
  • 在内存中维持一个变量
  • 通过保护变量的安全实现js私有属性和私有方法(不能被外部访问)

使用闭包的注意点

  由于闭包会携带 包含它的函数 的作用域,因此会比其他函数占用跟多的内存。过度使用闭包可能会导致内存占用过多


站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

2.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/8653

关闭

Js中的闭包与高级函数

在JavaScript中,函数是一等公民。JavaScript是一门面向对象的编程语言,但是同时也有很多函数式编程的特性,如Lambda表达式,闭包,高阶函数等,函数式编程时一种编程范式。

使用闭包的方式实现一个累加函数 addNum

使用闭包的方式实现一个累加函数 addNum,参数为 number 类型,每次返回的结果 = 上一次计算的值 + 传入的值

Js闭包的实现原理和作用

闭包的概念:指有权访问另一个函数作用域中的变量的函数,一般情况就是在一个函数中包含另一个函数。闭包的作用:访问函数内部变量、保持函数在环境中一直存在,不会被垃圾回收机制处理

JavaScript之闭包

闭包(closure)是掌握Javascript从人门到深入一个非常重要的门槛,它是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。下面写下我的学习笔记~

JS闭包的应用(私有变量、珂理化、偏函数)

柯里化是把接受 n 个参数的 1 个函数改造为只接受 1个参数的 n 个互相嵌套的函数的过程。也就是fn(a, b, c)会变成fn(a)(b)(c)。偏函数和珂理化的区别是,不再强调单函数。例如1个入参返回2个入参函数。

我终于理解了闭包

闭包这个词一听就很高级,令人害怕。但实际上,闭包非常的强大,JS 的精髓之一就是闭包。实际上,我们经常在使用闭包,而不自知!

深入理解Js闭包

《JavaScript权威指南》:函数对象可以通过作用域链相互关联起来,函数体内部的变量可以保存在函数作用域内,这种特性称为“闭包”。不好理解?那就通俗点讲:所谓闭包,就是一个函数,这个函数能够访问其他函数的作用域中的变量。

闭包原理及题型

函数被调用之后,会创建一个执行环境及作用域链.函数被执行完之后就会被释放掉,闭包函数执行之后会保留当前活动变量在内部函数作用域链中,所以内部函数可以访问外部变量.

Js闭包有什么用?

相信很少有人能直接看懂这句话,因为他描述的太学术。我想用如何在Javascript中创建一个闭包来告诉你什么是闭包,因为跳过闭包的创建过程直接理解闭包的定义是非常困难的。

Js中的闭包

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式就是在一个函数内部创建另一个函数。来看下面的示例:

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!