当一个块或者函数嵌套在另外一个函数或函数中时,就发生了做用域嵌套。浏览器
遍历嵌套做用域规则:引擎从当前的执行做用域开始查找变量,若是找不到,就向上一级继续查找。直到抵达最外层的全局做用域, 不管找到仍是没找到,查找过程都会中止。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的实例做为依赖参数,并能响相应的使用它。
当函数能够记住并访问所在的词法做用域,即便函数是在当前词法做用域之外执行,这时就产生了闭包。
模块有两个主要特征: