资讯专栏INFORMATION COLUMN

JS之模仿块级作用域_立即执行函数

NoraXie / 3357人阅读

摘要:模仿块级作用域立即执行函数前言最近在细读高级程序设计,对于我而言,中文版,书中很多地方一笔带过,所以用自己所理解的,尝试细致解读下。语法如下这里是块级作用域以上代码定义并立即调用了一个匿名函数。

模仿块级作用域-立即执行函数

前言:最近在细读Javascript高级程序设计,对于我而言,中文版,书中很多地方一笔带过,所以用自己所理解的,尝试细致解读下。如有纰漏或错误,会非常感谢您的指出。文中绝大部分内容引用自《JavaScript高级程序设计第三版》。

JavaScript没有块级作用域的概念(ES5中没有)。这意味着在块语句定义的变量,实际上是在函数中而非语句中创建的。

function outputNumbers(count) {
    for( var i = 0; i < count; i ++ ) {
        console.log(i); // 0,1,2,3,4,5,6,7,8,9
    }
    console.log(i); //10
}

outputNumbers(10);

在函数outputNumbers()中定义了一个for循环, 而变量i的初始值被设置为0。
在Java、C++等语言中,变量i只会在for循环的语句中有定义,循环一旦结束,变量i就会被销毁。

可是在JavaScript中,变量只是定义在函数outputNumbers()的活动对象中的,因此从它有定义开始,就可以在函数内部随处访问它。

即使像下面这样错误地重新声明同一个变量,也不会改变它的值。

function outputNumbers(count) {
    // 注意变量提升 var i
    for(var i = 0; i < count;  i++) {
        console.log(i); // 0, 1, 2, 4, 5, 6, 7, 8, 9
    };

    var i;
    console.log(i); // 10
}

outputNumbers(10);

JavaScript从来不会告诉你是否多次声明了同一个变量;
遇到这种情况,它只会对后续的声明视而不见(不过,它会执行后续声明中的变量初始化)。

匿名函数可以用来模仿块级作用域并避免这个问题(其实就是立即执行函数), 一定要注意变量的生命周期,局部变量只在执行环境中存在,块级作用域其实就是立即执行函数,即刻产生一个作用域,块级作用域里面的变量只在块级作用域里面,避免了变量污染,隔离出一个独立的作用域(私有作用域)。

//语法如下

(function(){
    //这里是块级作用域
})()

以上代码定义并立即调用了一个匿名函数。
将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。
而紧随其后的另一对圆括号会立即调用这个函数。

这种语法,确实很不好理解。

来看下下面的例子

var someFunction = function() {
    //这里是块级作用域
};
someFunction();

这个例子先定义了一个函数,然后立即调用它。定义函数的方式是创建一个匿名函数,并把匿名函数赋值给变量someFunction。而调用函数的方式是在函数名称后面添加一对圆括号,即someFunction()。那么我们可不可以,声明函数和调用函数写在一块呢?

function(){
    //这里是块级作用域
}(); //出错

这段代码会导致语法错误,因为JavaScript将function关键字当做一个函数声明的开始。而函数声明后面不能跟圆括号。

如果我们在function关键字前面加一个运算符,这样就不会让JavaScript将function关键字当做函数声明的开始。解析器,就会依次从左往右解析代码。

//解析过程 运算符 => 函数声明function => 调用()
!function(){
    console.log("hi");
}(); // "hi"

+function(){
    console.log("hello");
}(); // "hello"


-function(){
    console.log("World");
}(); // "World"

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

无论在什么地方,只要临时需要一些变量,就可以使用私有作用域。

function outputNumbers(count) {

    //立即执行函数,隔离出一个独立的作用域,避免变量的污染
    //同时也是一个闭包, 能访问到外部函数中的count
    (function(){
        for(var i= 0; i < count;  i++) {
            console.log(i);
        }
    })();

    console.log(i); // error
    
}

outputNumbers(10); // 0,1,2,3,4,5,6,7,8,9 
//i is not defined

这种技术(使用私有作用域),经常在全局作用域使用。

**从而限制向全局作用域中添加过多的变量和函数。
因为会产生变量污染,私有作用域可以访问到全局变量,而全局变量访问不到私有作用域里面的变量。**

一般来说,我们都应该尽量少向全局作用域中添加变量和函数。
在一个由很多开发人员共同参与的大型应用程序中,过多的全局变量和函数很容易导致命名冲突。

而通过创建私有作用域,每个开发人员都可以使用自己的变量,又不必担心搞乱全局作用域。

(function(){

    var now = new Date();

    if(now.getMonth() == 0 && now.getDate() == 1) {
        console.log("Happy New Year!");
    }

})();

把上面这段代码放在全局作用域中,可以用来确定哪一天是1月1日。

如果到了这一天,就会向用户显示一条祝贺新年的信息。

其中的变量now现在是匿名函数中的局部变量,而我们不必在全局作用域中创建它。

这种做法可以减少闭包占用的内存问题,因为没有指向匿名函数的引用。只要函数执行完毕,就可以立即销毁其作用域链了。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/98849.html

相关文章

  • javascript---Symbol类型, 引用类型, 作用

    摘要:指针指针指针重要的时期说三遍由于对象类型为指针引用在变量复制方面,基本类型和引用类型也有所不同。在浏览器中,全局执行环境被认为是对象。 javascript---Symbol类型, 引用类型, 作用域 javascript的引用类型, 即对象类型是我们最常用的的类型, 其中有许多让我们需要注意的地方, 最新的 , ES6 的推出, 使得对象类型的属性名不仅仅可以是字符串类型,还可是Si...

    leejan97 评论0 收藏0
  • JavaScript闭包

    摘要:而闭包的妙处在于,当函数在执行完毕后它的活动对象不会被销毁,因为匿名函数的作用域链仍然在引用函数的活动对象它的作用域链会被销毁。 一、闭包 闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常用方式是,在一个函数内部创建另一个函数。 请看以下代码:我们在createComparisonFunction函数里创建了一个闭包 function createComparisonFun...

    Mr_houzi 评论0 收藏0
  • JS学习笔记(第7章)(函数表达式)

    摘要:递归闭包模仿块级作用域私有变量小结在编程中,使用函数表达式可以无需对函数命名,从而实现动态编程。匿名函数也称为拉姆达函数。函数声明要求有名字,但函数表达式不需要。中的函数表达式和闭包都是极其有用的特性,利用它们可以实现很多功能。 1、递归 2、闭包 3、模仿块级作用域 4、私有变量 5、小结 在JavaScript编程中,使用函数表达式可以无需对函数命名,从而实现动态编程。匿名函数也称...

    xiaokai 评论0 收藏0
  • js闭包的应用

    摘要:前言之前发了一篇文章,写了一些对于闭包的理解。现在补上闭包的应用篇,很惭愧因为严重的拖延症一直拖到现在。本文主要分享一些常见的闭包用法和分析,也希望能增加对闭包的理解。 前言 之前发了一篇文章,写了一些对于闭包的理解。现在补上闭包的应用篇,(很惭愧因为严重的拖延症一直拖到现在)。本文主要分享一些常见的闭包用法和分析,也希望能增加对闭包的理解。 简单回顾 在之前的文章里,讲解了闭包的原理...

    didikee 评论0 收藏0
  • js高级程序设计-函数表达式-阅读笔记

    摘要:关于函数声明他的一个重要特征就是函数声明提升就是在执行代码之前会先读取函数声明这意味着可以把函数声明放到调用他的语句的后面将声明放到了后面关于函数表达式创建一个匿名函数然后赋值给一个变量函数体可以返回一个匿名函数返回的函数可以赋值给一个变量 关于函数声明 他的一个重要特征就是函数声明提升,就是在执行代码之前会先读取函数声明,这意味着可以把函数声明放到调用他的语句的后面 sayHi();...

    hiyang 评论0 收藏0

发表评论

0条评论

NoraXie

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<