【JavaScript】關於閉包

一、閉包是函數的代碼在運行過程當中的一個動態環境,是一個運行期的、動態的概念。
       閉包(又稱「詞法閉包」或「函數閉包」)是一個包含了非本地變量引用環境的函數。
二、變量在語法分析階段被初始化爲undefined。
//   標識符   ( 變量   ) 在定義後值爲 undefined
function myFunc() {
      alert(i);
      var i = 100;
}
// 輸出值老是undefined
myFunc();
myFunc();
//name在函數閉包內被聲明, 不會訪問到全局變量  name
var name = 'test';
function myFunc() {
      // 輸出undefined
      alert(name);
      var name = 100;
      // 輸出100 
      alert(name);
}
三、如下函數返回( return 子句)並不致使引用:
function myFunc() {
      function foo() {
      //...
      }
      return foo;
}
// 函數  foo() 在返回後當即被執行了,而後就會釋放
foo()();
四、引用:
對象屬性的引用:
      1)對象在構造時,使用   this   引用進入構造器函數
      2)對象在調用方法時,使用   this   引用進入函數
      3)某個函數使用   call/apply   方法調用,並傳入某個對象做爲   this   引用
      4)調用一個函數時,對象從參數入口傳入
被變量引用:
     var  func = myFunc(); // <-- 在這裏產生一個引用
五、函數閉包間的關聯性:
var checker;
function myFunc() 
{
     if (checker) {
            checker();
      }
      alert('do myFunc: ' + str);
      var str = 'test.';
      if (!checker) {
           checker = function() {
           alert('do Check:' + str);
           }
      }
      return arguments.callee;
}
  myFunc()();
// do myFunc:  undefined  第一次調用
//do Check:test.  第二次調用
// do myFunc:  undefined 第二次調用
六、
範例1:
var obj = new Object();
var events = { m1: "clicked", m2: "changed" };
for (e in events) {
      obj[e] = function(){
      alert(events[e]);
      };
}
// 顯示false, 代表是不一樣的函數實例
alert( obj.m1 === obj.m2 );
// 方法m1()與m2()都輸出相同值
// 其緣由,在於兩個方法都訪問全局閉包中的同一個upvalue 值e
obj.m1();
obj.m2();
範例2:
// 範例 2.1  在函數內保存數據
var obj = new Object();
var events = { m1: "clicked", m2: "changed" };
for (e in events) {
      obj[e] = function( aValue) { // 閉包 lv1
           return function() { // 閉包lv2
                alert(events[ aValue]);
           }
      }(e);
}
// 下面將輸出不一樣的值
obj.m1();

obj.m2(); 閉包

// 範例 2.2  在閉包內經過局部變量保存數據
for (e in events) {
      function() { // 閉包lv1
           var aValue = e;
           obj[e] = function() { // 閉包lv2
                alert(events[ aValue]);
           }
      }();

} app

// 範例 2.3  將值 e   交給函數實例保存
for (e in events) {
      (obj[e] = function() {
           // arguments.callee 指向匿名函數自身
           alert(events[arguments.callee .aValue]);
      }
      ) .aValue = e;

} 函數

// 範例 2.4  Function構造器
var obj = new Object();
var events = {m1: "clicked", m2: "changed"};
for (e in events) {
           obj[e] = new Function('alert( events["' + e + '"])');// 變量e被轉換爲字符串值來使
}

七、優先級:argsName(形式參數名) > arguments > funcName(函數名),其中arguments 是語言內定的標識符,無需聲明便可使用。  
// 示例1:輸出值'hi', 而非函數foo.toString()
function foo(foo) {
      alert(foo);
}
foo('hi');
// 示例2:輸出數值100 的類型'number', 而非參數對象arguments 的類型'object'
function foo2(arguments) {
      alert(typeof arguments);
}
foo2(100);
// 示例3:輸出參數對象arguments 的類型'object'
// (注:在JScript 中, arguments 做爲函數名能夠被聲明, 但調用該函數致使腳本引擎崩潰)
function arguments () {
      alert(typeof arguments);
}
arguments ();
八、局部變量 (varDecls)與函數形式參數:
     A. 當形式參數名與未賦值的局部變量名重複時   ,   取形式參數值;
     B. 當形式參數與有值的局部變量名重複時,取局部變量值。
第一種狀況:
function myFunc(str){
     var str;
     alert(str);
}
myFunc("not undefined");   //not undefined
第二種狀況:
function myFun(str){
     var str = "hello world";
     alert(str);
}
myFun("not undefined");  //hello world
九、使用Function()構造器建立的函數與函數直接量聲明、匿名函數不一樣,它在任意位置建立的實例,都處於全局閉包中。亦便是說, Function()的實例的upvalue 老是指向全局閉包。
var value = "hello world";
function myFunc(arg){
     var value = "welcome to here";
     var foo = new Function('alert(value)');
     foo();
}
myFunc();  //   "hello world"
 十、對象閉包:
var aObj = { value: 'hello' };
function foo() {
     with (aObj) {  // < --對象閉包
           var value = 1000;
            alert(aObj.value); // 顯示值: 1000
       }
       alert(value);
}
foo();    // 顯示'undefined'
十一、函數閉包與對象閉包既有相關性,也有各自的獨立性。對象閉包老是動態地添加在閉包鏈的頂端,而函數閉包則依賴於函數聲明時的、靜態的語法做用域限制。 
/**
* 兩種閉包的交叉做用  
*/
var obj = { value: 200 };
var value = 1000;
with (obj) { // <-- 對象閉包
      function foo() { // <-- 具名函數foo()的閉包
      value *= 2; // <-- 依賴於函數靜態位置所決定的閉包鏈
      }
      foo();     // with  的限定只對這一行有效
}
alert(obj.value);// 顯示 200
alert(value);   // 顯示 2000
十二、匿名函數的閉包如同對象閉包同樣,動態地添加到當前閉包鏈的頂端。
var obj = { value: 200 };
var value = 1000;
with (obj) { // <-- 對象閉包
    obj. foo =   function ()  {   // <-- 匿名函數的閉包
      value *= 2;   //   <-- 依賴於函數閉包所在的當前閉包鏈:with所打開的obj對象閉包
      }
    obj. foo();  
}
/**
* 即便該匿名函數沒 有添加爲對象  obj  的方法
*而僅是即用即聲明,那麼它所操做的仍然是對象 閉包中的  value 
*/
with (obj) { // <-- 對象閉包
      void  function ()  {   // <-- 匿名函數的閉包
      value *= 2;   //  <-- 依賴於函數閉包所在的當前閉包鏈:with所打開的obj對象閉包
      }();
}
// 顯示 400
alert(obj.value);
// 顯示 1000
alert(value);
1三、eval:
     解決eval做用域的方法:with ( objContext )eval (strScript) 。
     如:with ( window )eval (strScript) ; //eval在 全局做用域中執行
相關文章
相關標籤/搜索