详解js中常见函数及IIFE(立即执行函数)

2022-02-09  本文已影响0人  wylb868

1. 常见函数

//函数声明:使用function关键字声明一个函数,再指定一个函数名,叫函数声明。
function foo(){     
  var a = 8;
  console.log(a);
}
foo();  //调用函数

//函数表达式 :使用function关键字声明一个函数,但未给函数命名,最后将匿名函数赋予一个变量,叫函数表达式,这是最常见的函数表达式语法形式。
var foo = function () {
  var a = 8;
  console.log(a);
};
foo();  //调用函数

//匿名函数:使用function关键字声明一个函数,但未给函数命名,所以叫匿名函数.
//匿名函数属于函数表达式,匿名函数有很多作用,赋予一个变量则创建函数,赋予一个事件则成为事件处理程序或创建闭包等等。
function () {}; 

函数声明和函数表达式不同之处在于:

  1. Javascript引擎在解析javascript代码时会‘函数声明提升’(Function declaration
    Hoisting)当前执行环境(作用域)上的函数声明,而函数表达式必须等到Javascirtp引擎执行到它所在行时,才会从上而下一行一行地解析函数表达式。
  2. 函数表达式后面可以加括号立即调用该函数(所有IIFE在函数外面加()以表示其为函数表达式,不是函数声明),函数声明不可以,只能以fnName()形式调用 。

2. IIFE(立即执行函数)

(function foo(){
  var a = 8;
  console.log(a);
})();

上面函数声明和IIFE两种写法达到的目的是相同的,都是声明了一个函数foo并且随后调用函数foo。
如果只是为了立即执行一个函数,显然IIFE所带来的好处有限。

3. 为什么需要IIFE

实际上,IIFE的出现是为了弥补JS在scope方面的缺陷:JS只有全局作用域(global scope)、函数作用域(function scope),从ES6开始才有块级作用域(block scope)。对比现在流行的其他面向对象的语言可以看出,JS在访问控制这方面是多么的脆弱!那么如何实现作用域的隔离呢?在JS中,只有function才能实现作用域隔离,因此如果要将一段代码中的变量、函数等的定义隔离出来,只能将这段代码封装到一个函数中。

在我们通常的理解中,将代码封装到函数中的目的是为了复用。在JS中,当然声明函数的目的在大多数情况下也是为了复用,但是JS迫于作用域控制手段的贫乏,我们也经常看到只使用一次的函数:这通常的目的是为了隔离作用域了!既然只使用一次,那么立即执行好了!既然只使用一次,函数的名字也省掉了!这就是IIFE的由来。

IIFE 常见形式
(function () {
    var aName = "Barry";   
})();
aName // 错误,变量未定义( IIFE内部变量在外部无法直接访问)

var result = (function () {
    var name = "Barry";
    return name;
})();
result; // IIFE定义给一个变量,变量获取的是返回值,而非 IIFE函数

//JSLint 的版本
(function () {
    var aName = "Barry";
}());

//Arrow function 版本
(() => {
    var aName = "Barry";
})();

//Async function 版本
(async function () {
    var aName = "Barry";
})();

(async () => {
    var aName = "Barry";
})();

//传入参数
((param1, param2, param3, ...) => {
    var aName = "Barry";
})(param1, param2, param3, ...);
//对于常见的(function($){...})(jQuery);即是将实参jQuery传入函数function($){},通过形参$接收

4.其他函数形式

4.1 上述IIFE函数中,最开始的那个括号,可能会由于js中自动分号插入机制而引发问题。例如:
let a = b + c
(() => {
    var aName = "Barry";
})(); //可能会出错
//该处有可能被解析为c()而开始执行。所以有的时候,可能会看到这样的写法:;(function (){...}()),前边的分号可以认为是防御型分号。如:
let a = b + c
;(() => {
    var aName = "Barry";
})();
4.2 $(function(){...});$(document).ready(function(){/*...*/})的简写形式,是在DOM加载完成后执行的回调函数,并且只会执行一次。在页面中出现多次的话,会按先后顺序依次执行。
$(document).ready(function(){
    console.log('a');
})
//等价于
$(function(){
    console.log('a');
})
上一篇下一篇

猜你喜欢

热点阅读