作用域
- 作用域是一个函数在执行时的执行环境。
- 作用域中存在变量声明提升,变量包括普通变量和函数变量,因此变量声明也包括普通变量声明(var a)和函数变量声明(function fun() { },注意var f = function() {}是函数表达式),变量声明会提升到函数第一行代码执行之前。
- 函数作用域的变量来源有三个:函数参数——源于作用域内部;函数内部声明的变量,包括普通变量和函数变量——源于作用域的内部;函数外部的变量。
- 函数只有在被调用的时候,作用域才存在,在函数还没有开始执行的时候,开始创建函数的作用域:函数形参的声明,函数变量的声明,普通变量的声明,函数内部this的指针赋值。
5.变量声明需要强调:函数形参在声明的时候已经指定形参的值;在函数变量的生命中,会覆盖以前声明的同名变量;普通变量声明,不会覆盖以前声明的同名变量。 - 只有变量声明结束后,函数才开始执行代码!!!
作用域链
由于函数是可以嵌套的,函数B嵌套在A里,所以可以引用A的作用域,这种函数嵌套就形成了所谓的作用域链。当在自身作用域中找不到该变量的时候,就会沿着作用域链向上一层去找,如果在全局作用域还没有找到就会抛出异常。
闭包
- 闭包是可以访问另一个函数作用域的函数,创建闭包的方式就是在一个函数内部创建另一个函数。
function A(){
var a=1;
function B(){ //闭包函数,函数b能够访问函数a的作用域。所以, 像类似这么样的函数,我们就称为闭包
}
}
- 闭包会导致变量污染,内存泄漏。
(1)变量污染是由于对于闭包函数来说,外部作用域的变量相当于静态变量,所以在调用闭包函数时会更改外部变量的值。
var funB,
funC;
(function() {
var a = 1;
funB = function () {
a = a + 1;
console.log(a);
}
funC = function () {
a = a + 1;
console.log(a);
}
}());
funB(); //2
funC(); //3.
解决污染的办法:思路——既然外部作用域的变量是静态的,那么将其拷贝到内部作用域就可以随意更改而不影响外部作用域变量的值,至于怎么拷贝,当然是用传参的方式。
var funB,funC;
(function () {
var a = 1;
(function () {
funB = function () {
a = a + 1;
console.log(a);
}
}(a));
(function (a) {
funC = function () {
a = a + 1;
console.log(a);
}
}(a));
}());
funB()||funC(); //输出结果全是2 另外也没有改变作用域链上a的值。
(2)内存泄漏就是内存溢出,也就是内存空间不够用
var fun = undefined;
function A() {
var a = 1;
fun = function () {
}
}
只要函数fun存在,那么变量a就会一直存在,也就是函数A的作用域一直得不到释放,其作用域链上的空间也得不到释放,如果作用域链上是一个占用内存很大的DOM操作,就会发生内存泄漏。