Javascript中的闭包
前面的话:
闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它。下面是作者从作用域链慢慢讲到闭包以及在后面提到了一些闭包的高级用法。下面大家一起来学习Javascript中的闭包。
谈一谈JavaScript作用域链
当执行一段JavaScript代码(全局代码或函数)时,JavaScript引擎会创建为其创建一个作用域又称为执行上下文(Execution Context),在页面加载后会首先创建一个全局的作用域,然后每执行一个函数,会建立一个对应的作用域,从而形成了一条作用域链。每个作用域都有一条对应的作用域链,链头是全局作用域,链尾是当前函数作用域。
作用域链的作用是用于解析标识符,当函数被创建时(不是执行),会将this、arguments、命名参数和该函数中的所有局部变量添加到该当前作用域中,当JavaScript需要查找变量X的时候(这个过程称为变量解析),它首先会从作用域链中的链尾也就是当前作用域进行查找是否有X属性,如果没有找到就顺着作用域链继续查找,直到查找到链头,也就是全局作用域链,仍未找到该变量的话,就认为这段代码的作用域链上不存在x变量,并抛出一个引用错误(ReferenceError)的异常。
看下面的例子:
//定义全局变量color,对于全局都适用,即在任何地方都可以使用全局变量color
var color = "red";
function changeColor(){
//在changeColor()函数内部定义局部变量anotherColor,只在函数changeColor()里面有效
var anotherColor = "blue";
function swapColor(){
//在swapColor()函数内部定义局部变量tempColor,只在函数swapColor()里面有效
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
//这里可以访问color、anotherColor和tempColor
console.log(color); //blue
console.log(anotherColor); //red
console.log(tempColor); //blue
}
swapColor();
//这里只能访问color,不能访问anotherColor、tempColor
console.log(color); //blue
console.log(anotherColor); //anotherColor is not defined
console.log(tempColor); //tempColor is not defined
}
changeColor();
//这里只能访问color
console.log(color); //blue
console.log(anotherColor); //anotherColor is not defined
console.log(tempColor); //tempColor is not defined
还有几个坑需要注意一下:
1、var和函数的提前声明
var color = "red";
function changeColor(){
var color = "yellow";
return color;
}
var result = changeColor();
console.log(result);
再如:
function fn(a) {
console.log(a);
var a = 2;
function a() {}
console.log(a);
}
fn(1);
//输出:function a() {} ,2
2、Javascript中没有块级作用域,但是有词法作用域,比如:
function f1(){var a=1;f2();}
function f2(){return a;}
var result = f1();
console.log(result);
//输出结果:a is not defined
3、在函数内部不用var关键字申明变量,则默认该变量为全局变量,比如:
function add(a,b){
var sum = a+b;//次世代sum为add函数内部的变量,仅限在函数内部使用,在函数外面不可以使用
return sum;
}
var result = add(1,2);
console.log(result); //3
console.log(sum); //sum is not defined
//不使用var关键字声明变量
function add(a,b){
sum = a+b;//此时的sum为全局变量,在函数之外也可以调用
return sum;
}
var result = add(1,2);
console.log(result); //3
console.log(sum); //3
补充:
在JavaScript中如果不创建变量,直接去使用,则报错:
1
2
console.log(xxoo);
// 报错:Uncaught ReferenceError: xxoo is not defined
JavaScript中如果创建值而不赋值,则该值为 undefined,如:
1
2
3
var xxoo;
console.log(xxoo);
// 输出:undefined
在函数内如果这么写:
1
2
3
4
5
6
7
function Foo(){
console.log(xo);
var xo = 'seven';
}
Foo();
// 输出:undefined