闭包闭包
闭包函数
函数对象之间能够经过做用域链相互关联起来,函数体内部的变量均可以保存在函数做用域内spa
这种特性称作“闭包”。对象
什么是变量?ip
变量就是为一切事物赋的一个name;作用域
var的做用,初始化变量。源码
变量做用域io
程序源码中定义这个变量的区域就就是变量做用域。(名字放在什么地方了)console
全局变量拥有全局做用域,在js代码的任何地方都是有定义的。(这个名字很响亮)function
在函数体内声明的变量在函数体内有效,他们是局部变量,函数参数也是局部变量他们只在函数体内有定义。(里层的能拿到的外层的值,外层的拿不到里层的值)
在函数体内,同名的局部变量优先级要高于同名的全局变量,函数参数也是一个局部变量。
实例1: var scopte = “gloabl”;
function checkscope(){
var scope = “local”;
return scope;
}
checkscope() // “local”;
实例2:var attri = 100; //全局变量与函数参数同名,全局变量被遮盖。
function fuck( attri ){
alert(attri);
}
fuck(10); //10
实例3:
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function nested(){
var scope = "nested scope";
return scope;
}
return nested();
}
checkscope(); // “nested”;
js中没有块级做用域,取而代之的是函数做用域。
变量在声明的函数体以及这个函数体嵌套的任意函数体内都是有定义的。
声明提早 (遇到var的地方就会声明提早)
实例4:
function test(o){
/*i在整个函数体内均是由定义的*/
var i = 0;
if( typeof o=="object"){
/*j 在函数体内是用定义的,不单单是在这个代码段*/
var j=0;
/*k在函数体内是有定义的,不单单是在循环内*/
for( var k=0; k<10;k++){
console.log(k); //输出0~9
}
console.log(k); //10
}
console.log(j); //j已经定义了,但可能没有初始化。
}
等价于
function test(o){
var i;
var j;
var k;
i = 0;
if( typeof o=="object"){
j=0;
for( k=0; k<10;k++){
console.log(k);
}
console.log(k);
}
console.log(j);
实例5:
var scope = "global";
function f(){
console.log(scope); //调用f()输出undefined声明提早
var scope = "local"; //虽然不是第一行代码,可是实际scope已经声明了。
console.log(scope) //调用f()输出local;
}
等价于
var scope = “global”;
function f(){
var scope ;
console.log(scope);
scope = “local”;
console.log(scope);js中没有块级做用域,取而代之的是函数做用域。
}
做用域链( 做用域链是特殊的对象列表object-List )
定义函数的是很建立做用域对象,建立的做用域对象组成做用域链。
谈论做用域的时候要声明是哪段代码。就像咱们某人的时候要说明是哪个人。0
每一段JavaScript代码都有一个与之关联的做用域链,(js中没有块级做用域,取而代之的是函数做用域。)这个做用域链是一个对象列表。对象列表中定义了这段代码做用域中的对象。
var 建立的变量时不可配置的,不可经过delete操做符删除。
全局变量在程序中始终是有定义的,局部变量在声明的函数体内以及所嵌套的函数体内始终是由定义的。
若是将局部变量看作自定义对象的属性的话,能够换个角度来解读变量做用域,每一段js代码都有一个与之关联的做用域链,做用域链是一个对象列表(object-List),object-List定义了这段码做用域中的变量。当js须要变量x的时候(这个时候称做变量解析),它会从object-List中第一个对象开始查找,若是用这个变量x就直接使用,没有查找下一个object-List中的下一个对象,若是查询了全部的object-List对象中都没有x这个变量,则抛出一个引用错误。
做用域链类型
(1)js的最顶层代码中(不包含任何函数定义内的代码),保存的做用域链由1个全局对象组成。
(2)在定义不包含嵌套的函数体内,保存的做用域链由2个对象组成,第1个对象是定义函数参数和局部变量组成的,第2个是全局对象。
(3)在定义一个嵌套的函数体内,保存的做用域链上至少包含3个对象,第1个是嵌套函数内的参数和局部变量组成的对象,第2个对象是外层函数的参数和局部变量组成的,第3个对象是全局对象。
做用域链的建立规则
当定义一个function时,这个function实际上保存了一个做用域链object-List,当调用这个function时,这个function建立一个新的object(相似于经过构造函数建立对象)来保存它本身的局部变量,而后将这个建立的object添加到保存的那个做用域链object-List上,原来的object-List就增长了一个对象,
function a(){ var c ; } //建立这个函数的时候保存了一个object-List
a() //调用这个函数的时候建立了一个新的object来保存本身的局部变量,并将这个对象添加到做用域链object-List中,使定义该函数时的做用域链变长,而后建立一个新的更长的表示函数调用做用域的“链”。
实例7:
var i =0;
/*定义这个function的时候有2个做用域链 object-1为空,object-2 有var i这个变量值。*/
function a(){
i++;
alert(i);
}
/*调用这个函数的时候会建立一个变量对象改变定义function时候的做用域链,object-1为空,object-2var i 发生改变*/
a(); //1
a(); //2
对于嵌套函数来说,每次调用外部函数,都会使定义该外部函数时的做用域链变长,因此内部嵌套函数每次的做用域链也会微妙的不一样。嵌套的里层函数做用域构成包含了外层函数的做用域链,外层函数的做用域发生改变,里层函数的做用域链也会开始改变。
调用函数是什么意义?