03月08, 2019

JS基础(5)——函数(1)——扩展:立即执行函数

本章为 5-1 函数基础介绍章节的扩展内容。

立即执行的函数表达式的英文全称为 Immediately Invoked Function Expression,简称就为 IIFE。这是一个如它名字所示的那样,在定义后就会被立即调用的函数。

我们在调用函数的时候需要加上一对括号,IIFE 同样如此。除此之外,我们还需要将函数变为一个表达式,只需要将整个函数的声明放进括号里面就可以实现。具体的语法如下:

(function(){
    // 函数体
})()

接下来我们来看一个具体的示例:

(function(){
    console.log("Hello");
})()
// Hello

IIFE 可以在执行一个任务的同时,将所有的变量都封装到函数的作用域里面,从而保证了全局的命名空间不会被很多变量名污染。
这里我可以举一个简单的例子,在以前我们要交换 2 个数的时候,往往需要声明第 3 个临时变量 temp

注:从 ECMAScript 6 开始已经不需要这么做了,直接使用解构就可以交换两个数了

var a = 3,b = 5;
var temp = a;
a = b;
b = temp;
console.log(a); // 5
console.log(b); // 3
console.log(temp); // 3

这样虽然我们的 2 个变量被交换了,但是存在一个问题,那就是我们在全局环境下也存在了一个 temp 变量,这就可以被称之为污染了全局环境。所以我们可以使用 IIFE 来解决该问题,如下:

var arr = [3, 5];
(function (arr) {
    var temp = arr[0];
    arr[0] = arr[1];
    arr[1] = temp;
})(arr)
console.log(arr); // [ 5, 3 ]
console.log(temp); // ReferenceError: temp is not defined

这是一个非常方便的功能,特别是有些时候我们在初始化一些信息时需要一些变量的帮助,但是这些变量除了初始化之后就再也不会用了,那么这个时候我们就可以考虑使用 IIFE 来进行初始化,这样不会污染到全局环境。

(function () {
    var days = ["星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
    var date = new Date();
    var today = [date.toLocaleDateString(), days[date.getDay()]];
    console.log(`今天是${today[0]},${today[1]},欢迎你回来!`);
})()
// 今天是2017-12-20,星期三,欢迎你回来!

这里我们只是想要输出一条欢迎信息,附上当天的日期和星期几,但是有一个很尴尬的地方在于上面定义的这些变量我们都只使用一次,后面就不会再用了,所以这个时候我们也是可以考虑使用 IIFE 来避免这些无用的变量声明。

通过 IIFE,我们可以对我们的代码进行分块。并且块与块之间不会互相影响,哪怕有同名的变量也没问题,因为 IIFE 也是函数,在函数内部声明的变量是一个局部变量,示例如下:

(function () {
    //block A
    var name = "Mr.Yan";
    console.log(`my name is ${name}`);
})();
(function () {
    //block B
    var name = "zhang";
    console.log(`my name is ${name}`);
})();
// my name is Mr.Yan
// my name is zhang

在 var 流行的时代,JavaScript 是没有块作用域的。

什么叫做块作用域呢?

目前我们所知的作用域大概有 2 种:全局作用域函数作用域。其中,全局作用域是指声明的变量可在当前环境的任何地方使用。函数作用域则只能在当前函数所创造的环境中使用。

块级作用域是指每个代码块也可以有自己的作用域,比如在if块中声明一个变量,就只能在当前代码块中使用,外面无法使用。

用 var 声明的变量是不存在块级作用域的,所以即使在if块中用 var 声明变量,它也能在外部的函数或者全局作用域中使用。

function show(valid) {
    if (valid) {
        var a = 100;
    }
    console.log('a:', a);
}
show(true); // a: 100

这个例子中,a变量是在if块中声明,但是它的外部仍然能输出它的结果。

解决这个问题有 2 种方法,第一:使用 ECMAScript 6 中的 let 关键字声明变量,这样它就有块级作用域。第二:使用 IIFE,示例如下:

function show(valid) {
    if (valid) {
        (function () {
            var a = 100;
        })();
    }
    console.log('a:', a);
}
show(true); // ReferenceError: a is not defined

当然,只要浏览器支持,建立尽量使用 let 的方式来声明变量。

本文链接:http://www.yanhongzhi.com/post/js-basis-23.html

-- EOF --

Comments