JavaScript 匿名立即自执行函数

2019-2-2 23:38| 作者: admin| 查看: 4299| 评论: 0|来自: 蚂蚁部落

匿名自执行函数在当前应用非常广泛,通过它可以避免很多编程中常见问题。

下面将通过代码实例对其进行详细介绍,文本主要涵盖如下几个方面内容:

(1).什么是匿名立即自执行函数。

(2).匿名函数的主要应用方式。

一.匿名立即自执行函数:

匿名立即自执行函数是一种函数应用方式,可以使匿名函数创建之后立即执行。

它并不是ES中定义的一个标准术语,只是对此种应用方式的一种贴切的描述。

创建函数的方式有两种,一种是函数声明方式,一种是函数表达式方式。

本文对于函数的创建不做过多介绍,具体参阅JavaScript function 函数一章节。

函数声明方式创建的函数必定是具名函数,表达式方式创建的函数可以是匿名函数,也可以是具名函数。

代码实例如下:

[JavaScript] 纯文本查看 复制代码
// 具名函数
let funcJ = function f() {}
// 匿名函数
let funcN = function() {}

不要想当然认为funcN是函数的名称,只是一个变量而已,变量值是一个匿名函数。

既然要执行,自然要调用匿名函数,代码实例如下:

[JavaScript] 纯文本查看 复制代码运行代码
(function(){
  console.log("蚂蚁部落");
})()

上面代码会立即打印出字符串"蚂蚁部落",但是上述方式并推荐使用,代码修改如下:

[JavaScript] 纯文本查看 复制代码运行代码
(function(){
  console.log("蚂蚁部落");
}())

调用匿名函数的小括号应该在小括号之内。

虽然第一种写法在语法上完全没有问题,但是第二种写法看起来更像一个整体。

再额外介绍一个知识点,标准规定,凡是function关键字出现在代码的行首,那么代码毕竟被解读为语句。

表达式返回一个值,但是语句并不能,所以如下方式调用函数是错误的:

[JavaScript] 纯文本查看 复制代码
function func(){}()

但是我们可以先转换为一个表达式,然后再调用,代码实例如下:

[JavaScript] 纯文本查看 复制代码
(function func(){})()

将函数放入小括号后,形成一个表达式,表达式能够返回一个值,也就是函数对象。

二.匿名函数主要应用方式:

(1).避免作用域命名污染:

函数可以生成一个函数作用域,全局作用域变量和此函数作用域中的同名变量不会产生污染。

这个一点非常容易理解,看如下代码实例:

[JavaScript] 纯文本查看 复制代码运行代码
let webName="百度";
(function(){
    let webName="蚂蚁部落";
    console.log(webName);
}())
console.log(webName);

代码运行效果截图如下:

a:3:{s:3:\"pic\";s:43:\"portal/201902/02/234117zfsmpd098m64spc7.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

再来看一个常见的应用,比如页面要引入两个文件a.js与b.js,这两个文件中,都声明了变量webName。

那么同时引入的时候,就可能会产生冲突导致问题,比如后面的变量覆盖前面的,只要将各自文件的js代码放入匿名自执行函数即可解决此问题,代码如下:

[JavaScript] 纯文本查看 复制代码
// a.js
(function() {
  var webName = "蚂蚁部落";
})();
// b.js
(function() {
  var webName = "百度";
})();

(2).提升性能:

这一点可能很多朋友不是太理解,下面进行一下演示。

[JavaScript] 纯文本查看 复制代码
(function(){
    // code
}(window))

上述代码为匿名函数传递参数window,如果匿名函数内有对window对象的引用,在一定程度上可以提升性能。

因为不用越过函数作用域向上级作用域查找window对象,减少了对作用域的查找操作。

(3).保存闭包状态:

首先看一段代码实例,如果不注意可能出现意想不到的问题,尤其会给新手带来不小的困扰。

[HTML] 纯文本查看 复制代码运行代码
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>蚂蚁部落</title>
<style>
ul li{
  width:300px;
  list-style-type:none;
  font-size:12px;
  line-height:30px;
  height:30px;
  cursor:pointer;
}
ul li span{
  float:right
}
</style>
<script>
window.onload=function(){
  var obox=document.getElementById("box");
  var lis=obox.getElementsByTagName("li");
  var odiv=document.getElementById("show");
  for(var index=0;index<lis.length;index++){
    lis[index].onclick= function(){
      odiv.innerHTML=index;
    } 
  }
}
</script>
</head> 
<body> 
<ul id="box">
  <li>蚂蚁部落一</li>
  <li>蚂蚁部落二</li>
  <li>蚂蚁部落三</li>
  <li>蚂蚁部落四</li>
  <li>蚂蚁部落五</li>
</ul>
<div id="show"></div>
</body> 
</html>

上述代码的初衷是,点击li元素可以将对应元素的索引位置写入div中。

但是结果却并非如此,点击任何一个li元素,在div中显示的数字都是5,好像逻辑上没有任何问题。

原因是这样的,当通过for循环为li元素注册事件处理函数,index的值也随之增加,当for循环结束之后,index的值到达5,点击li元素是for循环结束之后的事情,所以index值已经变成了5,本质原因是index的作用域是load事件处理函数。下面通过匿名函数修改如下:

[HTML] 纯文本查看 复制代码运行代码
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>蚂蚁部落</title>
<style>
ul li{
  width:300px;
  list-style-type:none;
  font-size:12px;
  line-height:30px;
  height:30px;
  cursor:pointer;
}
ul li span{
  float:right
}
</style>
<script>
window.onload=function(){
  var obox=document.getElementById("box");
  var lis=obox.getElementsByTagName("li");
  var odiv=document.getElementById("show");
  for(var index=0;index<lis.length;index++){
    lis[index].onclick=(function(index){
      return function(){
        odiv.innerHTML=index;
      } 
    })(index)
  }
}
</script>
</head> 
<body> 
<ul id="box">
  <li>蚂蚁部落一</li>
  <li>蚂蚁部落二</li>
  <li>蚂蚁部落三</li>
  <li>蚂蚁部落四</li>
  <li>蚂蚁部落五</li>
</ul>
<div id="show"></div>
</body> 
</html>

上面代码将index作为匿名函数的参数,这样index的作用域被封闭在独立的匿名函数中,相互不会影响。ES2015提供了块级作用域,现在看来上述方式就有点多余(不考虑浏览器兼容性问题的话),代码实例如下:

[HTML] 纯文本查看 复制代码运行代码
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>蚂蚁部落</title>
<style>
ul li{
  width:300px;
  list-style-type:none;
  font-size:12px;
  line-height:30px;
  height:30px;
  cursor:pointer;
}
ul li span{
  float:right
}
</style>
<script>
window.onload=function(){
  var obox=document.getElementById("box");
  var lis=obox.getElementsByTagName("li");
  var odiv=document.getElementById("show");
  for(let index=0;index<lis.length;index++){
    lis[index].onclick= function(){
      odiv.innerHTML=index;
    } 
  }
}
</script>
</head> 
<body> 
<ul id="box">
  <li>蚂蚁部落一</li>
  <li>蚂蚁部落二</li>
  <li>蚂蚁部落三</li>
  <li>蚂蚁部落四</li>
  <li>蚂蚁部落五</li>
</ul>
<div id="show"></div>
</body> 
</html>

只要将var修改成let即可,那么{}就可以形成一个块级作用域,var声明变量不具备此功能。

关于let与块级作用域可以参阅如下两篇文章:

(1).JavaScript let 命令一章节。

(2).JavaScript 块级作用域一章节。


鲜花

握手

雷人

路过

鸡蛋

最新评论

返回顶部