作用域与IIFE

Javascript的作用域

  • 全局作用域(global scope)
  • 函数作用域(function scope)
  • 块级作用域(block scope)

由于简单的脚本语言的影响,js不支持文件作用域(file scope),即每一个页面文件独享一个作用域

Javascript的作用域:示例

  // 当前文件被其它页面所引入时,则共享全局作用域
  let i = 1 
  functon myfunc(){
    // 函数作用域
    let i = 100 
    for(let i=1;i<10; i++){
      // 块级作用域(block scope),ES6+ 支持
      console.log( i)      
    }
  }

糟糕的javscript https://github.com/denysdovhan/wtfjs/blob/master/README-zh-cn.md

第一个问题:变量名冲突

var counter = 0;
function add(){ return ++counter;  }
console.log(add());//1
console.log(add());//2

counter变量用于保存状态,但如果放置于全局空间,即当前文件引入了另一个js文件,而该js文件中的脚本也使用了counter变量即变量名冲突,将形成冲突,怎么办?

闭包: 函数式风格

var add = (function(){
    var counter = 0;
    return function(){ return ++counter; }
})();
console.log(add())   // =>1
console.log(add())   // =>2
  • 上述代码先是定义了一个匿名函数,并且被立即执行。执行后的结果另一个匿名函数对象的引用
  • 利用了js中的闭包特性,来解决变量的生命周期(全局可用)和作用域(局部可见)的问题,从而实现了变量的本地化
  • 函数式编程的特性:函数可以被动态地定义,允许作为输入参数、输出参数。

第二个问题:函数名冲突

$()函数是个十分常用的名字,曾经有多个流行的js库都定义了$(),如Jquery、Prototype等。因此,当某页面需要同时引用这两个库或者当你的自编库也定义了$()函数。那么,如何避免冲突?

<script src="./jquery.js"></script>
<script src="./prototype.js"></script>
<script>
$('#info').text('该字段不能为空!');  // `$()`函数出现歧义
</script>

立即执行函数 Immediately Invoked Function Expression

类似如下的语句(闭包示例中也有),称之为立即执行函数(IIFE)

(function ($) {   
  $('#info').text('该字段不能为空!'); 
})(window.jQuery);

它解决了函数名冲突的问题:通过声明一个匿名函数,将$名字仅限于该匿名函数内部,然后立即执行该函数,由外部调用者传入一个外部函数的名字。类似一种多态的机制。

IIFE

function(w, d, $){...}(window, document, window.jQuery);

IIFE帮助开发者间接实现了一个局部化的作用域,从而:

  • 模块化: 外部函数和内部函数可以同名;不同的库只需要保持唯一的库名;一般来说,库名远远少于函数名且易于管理。
  • 多态:函数的接口不变,但行为各异
  • 性能提升:全局变量的局部化,减少对全局变量作用域的查找

参考

results matching ""

    No results matching ""