作用域与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帮助开发者间接实现了一个局部化的作用域,从而:
- 模块化: 外部函数和内部函数可以同名;不同的库只需要保持唯一的库名;一般来说,库名远远少于函数名且易于管理。
- 多态:函数的接口不变,但行为各异
- 性能提升:全局变量的局部化,减少对全局变量作用域的查找
参考
- https://developer.mozilla.org/zh-CN/docs/Glossary/%E7%AB%8B%E5%8D%B3%E6%89%A7%E8%A1%8C%E5%87%BD%E6%95%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F
- http://benalman.com/news/2010/11/immediately-invoked-function-expression/#iife
- https://www.cnblogs.com/xiezhi/p/5653130.html
- bootstrap代码解析 http://suqing.iteye.com/blog/1984131