首页 热点资讯 义务教育 高等教育 出国留学 考研考公
您的当前位置:首页正文

IIFE立即执行函数

2024-12-20 来源:化拓教育网

就是下面这样的的代码:

(function foo(){  
    console.log( "Hello!" );    
})(); 

关于IIFE书写方式

第一种情况:

function(){ /* code */ }(); // SyntaxError: Unexpected token (

解释:JavaScript在解析代码时,当遇到function关键字时,会默认把它当做一个函数声明,而不是函数表达式,如果没有把它显式的写成函数表达式,就报错,因为函数声明需要一个函数名。上面的报错是因为没有函数名(第一个左括号)。

第二种情况:

function foo(){ /* code */ }(); // SyntaxError: Unexpected token )

解释:在表达式后面加括号表示执行;此外,在函数声明一个语句,在语句后面加括号可等价为:

function foo(){ /* code */ }
(); // SyntaxError: Unexpected token )

相当于声明了函数foo,后面进行()的表达式操作。()表示分组操作符,内部表达式不能为空,所以报错,上面的报错是因为分组操作符内为空的错误。

第三种情况:

(function(){ /* code */ }());

为什么这样就能立即执行并且不报错呢?因为在javascript里,括号内部不能包含语句,当解析器对代码进行解释的时候,先碰到了(),然后碰到function关键字就会自动将()里面的代码识别为函数表达式而不是函数声明

因此,也可以这么写:

(function(){ /* code */ })();

此外,只要功能类似于()语句转化为表达式的方式都能用于IIFE,例如下面的写法都会生效:

false || function () {console.log('hello')}()
true && function () {console.log('hello')}()
'anything', function () {console.log('hello')}()

~function () {console.log('hello')}()
!function () {console.log('hello')}()
+function () {console.log('hello')}()
-function () {console.log('hello')}()

~(function () {console.log('hello')})() // 变种

第四种情况:

var i = function(){ return 10; }();

这样的写法把fucntion当做函数表达式,可以不加(),但是为了增加代码可读性,建议加上。

和闭包的配合

1. 保存函数内部变量状态

下面代码并不会像你想象那样的执行,因为i的值没有被锁住,当我们点击链接的时候,其实for循环已经执行完了,于是在点击的时候i的值其实已经是elems.length了。

var elems = document.getElementsByTagName( 'a' );
for ( var i = 0; i < elems.length; i++ ) {
  elems[ i ].addEventListener( 'click', function(e){
    e.preventDefault();
    alert( 'I am link #' + i );
  }, 'false' );
}

这样改写:

var elems = document.getElementsByTagName( 'a' );
for ( var i = 0; i < elems.length; i++ ) {
  (function( i ){
    // 其实代码中的 i 和外面的 i 是在不同的作用域里完全不同,比如:
    elems[ i ].addEventListener( 'click', function(e){
      e.preventDefault();
      console.log( 'I am link #' + i );
    }, 'false' );
  })( i );
}

IIFE代码中的i和外面的i是在不同的作用域里,完全不同的两个值,只是名字一样。

2. 局部变量、模块化

立即执行函数在模块化中也大有用处。用立即执行函数处理模块化可以减少全局变量造成的空间污染,构造更多的私有变量。

// 创建一个立即执行的匿名函数
// 该函数返回一个对象,包含你要暴露的属性
// 如下代码如果不使用立即执行函数,就会多一个属性i
// 如果有了属性i,我们就能调用counter.i改变i的值
// 对我们来说这种不确定的因素越少越好
 
var counter = (function(){
  var i = 0;
 
  return {
    get: function(){
      return i;
    },
    set: function( val ){
      i = val;
    },
    increment: function() {
      return ++i;
    }
  };
}());
 
// counter其实是一个对象
 
counter.get(); // 0
counter.set( 3 );
counter.increment(); // 4
counter.increment(); // 5
 
counter.i; // undefined i并不是counter的属性
i; // ReferenceError: i is not defined (函数内部的是局部变量)

总结

  • 能转化为函数表达式的操作都能构造IIFE
  • IIFE和普通函数类似,可以传参,有返回值
  • IIFE可以制造局部变量,用于模块化

参考

显示全文