什么是做用域?
在当前运行环境下,能够访问的变量或函数的范围。
做用域分为词法做用域和动态做用域。
词法做用域是在js代码编译阶段就肯定下来的; 对应的,with
和eval
语句会产生动态做用域。javascript
会产生新的做用域的状况:java
{}
(ES6)eval
举个例子说明做用域闭包
var a = 'hello'; function f1(){ var a = 1; console.log(a); } f1(); // 1 console.log(a); // hello
能够看到f1中的变量a只能在f1中有效,f1外部访问不到里面的a;因此在f1中的a,其做用域就只限定在f1中。函数
再来个新概念:做用域链性能
var a = 'hello'; function f1(){ console.log(a);// ps: f1中并未声明a } f1(); // hello
之因此输出hello, 是由于在f1中并未找到a的定义,此时程序并不会急于抛异常,而是会向调用f1的上一层寻找a的定义。若是没有,会继续再往上一层的上一层寻找,直到最顶层。
这样就造成了一个链式的做用域。code
什么是闭包?对象
一般来说,函数能够访问函数外面的变量;可是在函数外部,访问不到在函数里面定义的变量。ip
function f1(){ var a = 1; } console.log(a); // Uncaught ReferenceError: a is not defined
那么有没有可能访问到f1中的a呢?固然是有的, 看例子:内存
function f1(){ var a = 1; function f2(){ return a; } return f2; } var getA = f1(); console.log(getA()); // 1
咱们在f1中,添加了一个函数f2(实际上f2就能够看作一个闭包)。
通常状况下,当函数执行完毕时,里面的变量会被自动销毁。可是由于咱们把f2赋值给了外部的getA,因此f2不会被内存释放,同理f2中使用的a在f2的做用域中,也不会被释放,因此这个时候就能够访问到a。
而getA可以访问到a,这个在js的编译阶段就已经定型了(词法做用域)。作用域
官方”的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(一般是一个函数),于是这些变量也是该表达式的一部分。
相信不多有人能直接看懂这句话,由于他描述的太学术。其实这句话通俗的来讲就是:闭包就是可以读取其余函数内部变量的函数。
闭包的特色闭包能够在函数外部改变函数中的变量的值,若是你把函数做为对象、闭包做为方法、局部变量做为私有属性使用,则会改变该变量的值;闭包还会把函数中的变量的值存储于内存中,对内存消耗很大,因此滥用闭包的结果就是影响网页性能,IE中则可能致使内存泄露