加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员  
 
x
 
 本帖最后由 沉滞的剑 于 2016-6-14 15:40 编辑  
 
我不是学编程的,这个教程只是用来帮助新手迅速理解这几个概念的,所以用词和理解肯定有不准确的地方,但是对于写脚本来说还是足够的。 
 
 1.变量的作用域 
注意, 声明局部变量时要使用 var 关键词 
否则js会默认将其设为window的成员,成为全局变量 
例子1: 
var a = 3; function foo(){ var b = 3; console.log(a); console.log(b); } foo(); console.log(a); console.log(b); 输出:3,3,3,undefined 
 
 var a = 3;  
function foo(){  
var b = 3;  
console.log(a);  
console.log(b);  
}  
foo();  
console.log(a);  
console.log(b);  
输出:3,3,3,undefined  
 
  
结论1:在函数内部声明的变量b在函数外是访问不到的. 
反过来在全局声明的变量对所有函数都是可见的 
例子2: 
function foo(){   var a = 3;   function fun(){   var b = 3;   console.log(a);   console.log(b);   }   fun();   console.log(a);   console.log(b); } foo(); 
 
 function foo(){  
  var a = 3;  
  function fun(){  
  var b = 3;  
  console.log(a);  
  console.log(b);  
  }  
  fun();  
  console.log(a);  
  console.log(b);  
}  
foo();  
 
  
输出:3,3,3,undefined 
结论2:同样地, 局部函数内的变量对局部函数外是不可见的, 
而函数内的函数对局部函数是可见的 
也就是说在一对大括号{}里声明的变量对着这一层级内都是可见的 
2. 闭包 
如果我们想在外部读取局部变量的值,我们就需要用到闭包. 
举例: 
function foo(){     var n = 0;     return function fun(){     n++;     console.log(n);      } } a = foo(); //这里返回的是fun函数字面量 a(); a(); a(); foo()(); //这里()是一个运算符,代表运行的意思 // 第一次运行了foo返回了fun,第二次代表运行fun. foo()(); foo()();  输出: 1,2,3,1,1,1 
 
 function foo(){  
    var n = 0;  
    return function fun(){  
    n++;  
    console.log(n);   
    }  
}  
a = foo(); //这里返回的是fun函数字面量  
a();  
a();  
a();  
foo()(); //这里()是一个运算符,代表运行的意思  
// 第一次运行了foo返回了fun,第二次代表运行fun.  
foo()();  
foo()();   
输出: 1,2,3,1,1,1  
 
  
注意a();输出的量都是递增的,证明了n这个变量在内存里是保留了的。 
而foo()();是没有保留的,每次输出都是1. 
这里有一个垃圾回收的机制。 
因为foo()();运行结束后是没有变量指向它的所以它被回收了。 
每一次呼叫都是创建的新对象,运行结束后就立刻被销毁。 
而a()不是。它直接开辟了一块新内存来保存了这块数据。 
所以fun函数会被保存。 
而fun外面的函数foo也会被保存。局部变量n的值也会被记录。 
我们通过return fun(){.....}来达到了访问foo的局部变量n的目的 
这就是闭包。简单理解就是在域外访问域内的数据。 
3.匿名函数 
匿名函数, 简单说没有函数名的函数就是匿名函数。 
匿名函数也同样遵守变量作用域的规则。 
比如 function(){console.log('Hello World')} 
其实它就是个函数字面量 
但是字面量本身是无法被调用的,无法被调用怎么呼叫呢? 
记得之前foo()()的用法么? 
首先第一步,把函数字面量变成函数对象. 
有很多方法: 
常用的(function(){console.log('Hello World')}) 
我喜欢的方法!function(){console.log('Hello World')} 
原理:将一个运算符放在旁边, 编译器会自动对字面量取值也就完成了转换. 
但是,到这里这个函数只是被声明了而没有被运行 
所以我们还需要一个()来运行它. 
比如例子: 
(function(){console.log('Hello World')})(); 
或者!function(){console.log('Hello World')}(); 
匿名函数在脚本里相当于一个壳, 在壳中声明的局部变量都不会被壳外访问到 
这就避免了被污染. 
但是壳中的数据可以通过闭包函数来访问, 它会被保存在内存里. 
就比如说很多脚本的参数都是写在匿名函数里但是可以通过闭包来访问和修改  
 
总结: 
变量的访问是有层级的,内部函数可以访问外部变量,但外部函数不可以访问内部变量。 
匿名函数是墙,把外部不需要知道和使用的数据包裹起来。 
闭包是桥梁,通过返回闭包函数来访问和修改需要访问但是却在墙内的数据。 
 
 
 
 |