做用域是指程序源代码中定义变量的区域。javascript
实际上描述的就是查找变量的范围,做用域必须有的两个功能就是存储变量以及查找变量,做用域就是发挥这两个做用以及更多做用的规则。java
做用域规定了如何查找变量,也就是肯定当前执行代码对变量的访问权限。闭包
JavaScript采用的是词法做用域模块化
在代码中任何地方都能访问到的对象拥有全局做用域函数
全局变量:设计
- 生命周期将存在于整个程序以内。
- 能被程序中任何函数或者方法访问。
- 在 JavaScript 内默认是能够被修改的。
JavaScript 采用词法做用域(lexical scoping),也就是静态做用域。code
带有关键字 var 的声明对象
var winValue = 10; console.log(window.winValue); // 10
不带有声明关键字的变量,JS 会默认帮你声明一个全局变量继承
function foo(value) { result = value + 1; // 没有用 var 声明 return result; }; foo(1); console.log(window.result); // 2 <= 挂在了 window全局对象上
函数做用域内,对外是封闭的,从外层的做用域没法直接访问函数内部的做用域。生命周期
在函数内部的变量权限称为函数做用域,有如下特色:
function bar() { var foo = 'test'; } console.log(foo); // Uncaught ReferenceError: foo is not defined
凡是由{}符号包裹起来的都是块做用域
for(let i = 0; i < 5; i++) { // ... } console.log(i); // Uncaught ReferenceError: i is not defined
在 for 循环执行完毕以后 i 变量就被释放了
做用域链:当访问一个变量时,解释器会首先在当前做用域查找,若是没有找到,就去父做用域找,直到找到该变量或者不在父做用域中,这就是做用域链。
var a = 1 function foo () { var b = 2 console.log(a) } foo() // 1 console.log(b) // Uncaught ReferenceError: b is not defined
从上面代码的执行结果能够看出,foo 函数取到了它外部的变量 a, 而最外层的 console.log(b) 操做并没能取得 foo 函数里面的变量 b。
若是去查找一个普通对象的属性,可是在当前对象和其原型中都找不到时,会返回undefined;但查找的属性在做用域链中不存在的话就会抛出ReferenceError。
闭包是指有权访问另一个函数做用域中的变量的函数
在javascript中,只有函数内部的子函数才能读取局部变量,因此闭包能够理解成"定义在一个函数内部的函数"。在本质上,闭包是将函数内部和函数外部链接起来的桥梁。
之因此出现闭包是由于JS的垃圾回收机制,JS自己为了不解释器过量消耗内存,形成系统崩溃,自带有一套垃圾回收机制,垃圾回收机制可以检测到一个对象是否是无用的。检测到以后,就会把它占用的内存释放掉。可是实际工做中,咱们也会须要一些变量不那么及时的被清理,因此就出现了闭包,用来达成这个效果。
function getOuter(){ var name = 'jacky'; function getName(str){ console.log(str + name); // 能够访问getName函数外部的name } return getName('名字是:'); } getOuter(); // 名字是:jacky
再来看下面一段代码:
function bar() { var x = 1; return function () { var y = 2; return x + y; } } var foo = bar(); // 这一句执行完,变量x并无被回收,由于要内部函数还须要引用 console.log(foo()) // 3 执行内部函数,引用外部变量x
上面代码中,在全局执行上下文中定义了一个函数bar和变量foo,函数bar内部返回一个匿名函数,因此此刻匿名函数的做用域链初始化为包含了全局变量对象和bar中的变量对象。
当执行var foo = bar()时,把函数bar的执行上下文压入栈,当bar执行完后,其执行上下文应该弹出栈,可是由于bar内部的匿名函数做用域链还引用这bar函数内的变量x,因此bar的执行上下文得不到释放,这样就造成了闭包。
1.设计私有的方法和变量(封装,定义模块)。
var counter = (function(){ var privateCounter = 0; //私有变量 function change(val){ privateCounter += val; } return { increment:function(){ change(1); }, decrement:function(){ change(-1); }, value:function(){ return privateCounter; } }; })();
2.匿名函数最大的用途是建立闭包。减小全局变量的使用。从而使用闭包模块化代码,减小全局变量的污染。
var objEvent = objEvent || {}; (function() { var addEvent = function() { // some code } function removeEvent() { // some code } objEvent.addEvent = addEvent objEvent.removeEvent = removeEvent })()
addEvent 和 removeEvent 都是局部变量,但咱们能够经过全局变量 objEvent 使用它
javascript中,若是一个对象再也不被引用,那么这个对象就会被垃圾回收机制回收。若是两个对象互相引用,而再也不被第3者所引用,那么这两个互相引用的对象也会被回收。
即释放对闭包的引用,使引用变量为null。
优势:
缺点:
造成闭包即要把一个函数当成值传递,并且该函数还引用这另外一个函数的做用域链使得被引用的函数不能被回收,使用不当容易形成内存泄漏;