當一個塊或者函數嵌套在另外一個函數或函數中時,就發生了做用域嵌套。瀏覽器
遍歷嵌套做用域規則:引擎從當前的執行做用域開始查找變量,若是找不到,就向上一級繼續查找。直到抵達最外層的全局做用域, 不管找到仍是沒找到,查找過程都會中止。bash
做用域是一套規則,用於肯定在何處以及如何查找變量(標誌符)。 若是查找目的是對變量進行賦值,就是執行LHS查詢 若是查找目的是獲取變量的值,就是執行RHS查詢閉包
做用域主要兩種工做模式:詞法做用域和動態做用域app
window.a
。經過這種技術能夠訪問那些被同名變量鎖遮蔽的全局變量。但非全局變量若是被遮蔽了,不管如何都沒法被訪問到。詞法做用域意味着做用域是由代碼書寫時候函數聲明的位置來決定的。函數
函數做用域是指,屬於這個函數的所有變量均可以在整個函數的範圍內使用以及複用(事實上在嵌套的做用域中也可使用)。ui
不該該這樣:spa
function doSomething(a) {
b = a + doSomethingElse(a * 2);
console.log(b * 3);
}
function doSomethingElse(a) {
return a - 1;
}
var b;
doSomething(2);
複製代碼
而是應該這樣, 隱藏變量:調試
function doSomething(a) {
function doSomethingElse(a) {
return a - 1;
}
var b;
b = a + doSomethingElse(a * 2);
console.log(b * 3);
}
doSomething(2);
複製代碼
「隱藏」做用域中的變量和函數所帶來的另外一個好處,是能夠避免同名標識符之間的衝突,兩個標識符可能具備相同的名字可是用途卻不同,無心間可能形成命名衝突。 衝突會致使變量的值被意外覆蓋。code
例如以下函數:cdn
setTimeout(function() {
console.log('I waited 1 second');
}, 1000);
複製代碼
這叫作匿名函數表達式。 匿名函數表達式書寫起來簡單快捷,可是有幾個缺點:
arguments.callee
引用。行內函數表達式很是強大且有用----匿名和具名之間的區別並不會對這一點有任何影響。給函數表達式指定一個函數名能夠有效解決以上問題。因此,最好始終給函數表達式命名。
setTimeout(function timeoutHandler() { // 有名字了
console.log('I waited 1 second');
}, 1000);
複製代碼
(function(){})()
和 (function(){}())
當函數能夠記住並訪問所在的詞法做用域時,就產生了閉包,即便函數是在所在詞法做用域之外被執行,這個引用,就叫作閉包。
模塊模式須要具有兩個必要條件:
一個具備函數屬性的對系那個自己並非真正的模塊。從方便觀察的角度看,一個從函數調用鎖返回的,只有數據屬性而沒有閉包函數得對象並非真正的模塊。
大多數模塊依賴加載器/管理器本質上都是將這種模塊定義封裝進一個友好的API。
var MyModules = (function Manager() {
var modules = {};
function define(name, deps, impl) {
for (var i = 0; i < deps.length; i++) {
deps[i] = modules[deps[i]];
}
modules[name] = impl.apply(impl, deps);
}
function get(name) {
return modules[name];
}
return {
define: define,
get: get
};
})();
MyModules.define('bar', [], function() {
function hello(who) {
return 'let me introduce: ' + who;
}
return {
hello: hello
};
});
MyModules.define('foo', ['bar'], function(bar) {
var hungry = 'xiaofan';
function awesome() {
console.log(bar.hello(hungry).toUpperCase());
}
return {
awesome: awesome
};
});
var bar = MyModules.get('bar');
var foo = MyModules.get('foo');
console.log(bar.hello('xiaofan'));
foo.awesome();
複製代碼
foo
和bar
模塊都是經過一個返回公共API的函數來定義的。foo甚至接受bar的實例做爲依賴參數,並能響相應的使用它。
當函數能夠記住並訪問所在的詞法做用域,即便函數是在當前詞法做用域之外執行,這時就產生了閉包。
模塊有兩個主要特徵: