摘要:在函數內部定義的匿名函數的作用域鏈中,不包含外部函數的活動對象。在執行完畢以后,其執行環境的作用域鏈被銷毀,但是其活動對象不會被銷毀,因為匿名函數的作用域鏈中仍然引用著這個活動對象,直到匿名函數執行完畢后,才一起被銷毀。
函數表達式和函數聲明
函數聲明:function 函數名稱 (參數:可選){ 函數體 }
函數表達式:function 函數名稱(可選)(參數:可選){ 函數體 }
函數聲明只能出現在程序或函數體內。從語法上講,它們不能出現在Block(塊)({ ... })中。表達式和聲明存在著十分微妙的差別,函數聲明會在任何表達式被解析和求值之前先被解析和求值。無論變量在函數內何處聲明,在代碼執行階段,變量都會在提到函數開始執行之前被聲明,而函數聲明發生在更早的階段。
var foo; if (true) { foo = function (){ console.log(1); }; }else { foo = function (){ console.log(2); }; } foo(); // 1 先聲明foo變量,在代碼處理的第一步,按照程序執行順序,創建函數表達式并賦值給foo。 if (true) { function foo(){ console.log(1); } }else { function foo(){ console.log(2); } } foo(); // 2 基于Gecko的瀏覽器 //1 函數聲明在代碼處理的第一步。function foo(){ console.log(2); }會覆蓋前面的操作。 alert(sum(10,10)); //20 function sum(num1, num2){ return num1 + num2; } alert(sum(10,10)); //causes an error var sum = function(num1, num2){ return num1 + num2; }; //變量sum的聲明還是放在第一步處理
命名函數表達式:var bar = function foo(){};需要注意的地方:這個名字只在新定義的函數作用域內有效(IE9以前版本的IE版本中)。命名函數表達式方便調試。
var f = function foo(){ return typeof foo; // foo是在內部作用域內有效 }; // foo在外部用于是不可見的 typeof foo; // "undefined" IE5-IE8中 " function" f(); // "function"調用模式
方法調用模式
當一個函數保存為對象的一個屬性時,我們稱它為方法。當一個方法被調用的時候,this被綁定到該對象。如果調用表達式包含一個提取屬性的動作xxx.xxx,那么它就是被當做方法來調用的。
函數調用模式
this被綁定到全局對象。
構造器調用模式
this被綁定到創建的新對象。
apply調用模式
apply允許我們選擇this的值,方法接受兩個參數,第一個是要綁定this的值,第二個是參數數值。第一個參數為null,undefined將會被替換成全局對象。嚴格模式use strict的時候不會被替換。
很多現代語言都推薦延遲聲明變量,js中推薦在函數體的頂部聲明函數中可能用到的所有變量。
JScript的Bug
例1:函數表達式的標示符泄露到外部作用域 typeof g; // "function" var f = function g(){}; IE9已經修復 例2:將命名函數表達式同時當作函數聲明和函數表達式 typeof g; // "function" var f = function g(){};
函數聲明會優先于任何表達式被解析,上面的例子展示的是JScript實際上是把命名函數表達式當成函數聲明了,因為它在實際聲明之前就解析了g
匿名函數匿名函數中this 一般指向window對象
XXXX.prototype.__XXX = function(){} 不是匿名函數
在編寫遞歸函數時,使用arguments.callee (但是es5嚴格模式下會報錯)比使用函數名安全。
函數中的變量對象就是活動對象。
無論什么時候在函數內部訪問一個變量時,就會從作用域鏈中搜索相應變量。一般來講,當函數執行完畢后局部活動對象將被銷毀。但是閉包情況有所不同。
在createComparisonFunction()函數內部定義的匿名函數的作用域鏈中,不包含外部函數createComparisonFunction()的活動對象。
var compare = createComparisonFunction("name");
var result = compare(obj1, obj2);
createComparisonFunction()在執行完畢以后,其執行環境的作用域鏈被銷毀,但是其活動對象不會被銷毀,因為匿名函數的作用域鏈中仍然引用著這個活動對象,直到匿名函數執行完畢后,才一起被銷毀。閉包會攜帶包含他的函數的作用域,占用內存較多。
閉包只能取得包含函數中變量最后保存的值。 function createFunctions() { var result = new Array(); for (var i = 0; i < 10; i++) { result[i] = function() { return i; }; } return result; } var funcs = createFunctions(); //every function outputs 10 for (var i = 0; i < funcs.length; i++) { document.write(funcs[i]() + "用閉包保存狀態
"); } 使用匿名函數再添加一層外部函數,多了一個閉包使原來的閉包滿足條件 function createFunctions() { var result = new Array(); for (var i = 0; i < 10; i++) { result[i] = function(num) { return function() { return num; }; }(i); } return result; } var funcs = createFunctions(); //every function outputs 10 for (var i = 0; i < funcs.length; i++) { document.write(funcs[i]() + "
"); }
閉包直接可以引用傳入的參數,利用這些被lock住的傳入參數,自執行函數表達式可以有效地保存狀態。
// 這個代碼是錯誤的,因為變量i從來就沒背locked住 // 相反,當循環執行以后,我們在點擊的時候i才獲得數值 // 因為這個時候i操真正獲得值 // 所以說無論點擊那個連接,最終顯示的都是I am link #10(如果有10個a元素的話) var elems = document.getElementsByTagName("a"); for (var i = 0; i < elems.length; i++) { elems[i].addEventListener("click", function (e) { e.preventDefault(); alert("I am link #" + i); }, "false"); } // 這個是可以用的,因為他在自執行函數表達式閉包內部 // i的值作為locked的索引存在,在循環執行結束以后,盡管最后i的值變成了a元素總數(例如10) // 但閉包內部的lockedInIndex值是沒有改變,因為他已經執行完畢了 // 所以當點擊連接的時候,結果是正確的 var elems = document.getElementsByTagName("a"); for (var i = 0; i < elems.length; i++) { (function (lockedInIndex) { elems[i].addEventListener("click", function (e) { e.preventDefault(); alert("I am link #" + lockedInIndex); }, "false"); })(i); } // 你也可以像下面這樣應用,在處理函數那里使用自執行函數表達式 // 而不是在addEventListener外部 // 但是相對來說,上面的代碼更具可讀性 var elems = document.getElementsByTagName("a"); for (var i = 0; i < elems.length; i++) { elems[i].addEventListener("click", (function (lockedInIndex) { return function (e) { e.preventDefault(); alert("I am link #" + lockedInIndex); }; })(i), "false"); }自執行函數表達式
利用了閉包的特性,可以避免全局變量
javascript語法中()內部不能包含語句,只能包含表達式。 (function () { /* code */ } ()); // 推薦使用這個
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91528.html
摘要:基礎鞏固基礎總結使用已經好幾年了,由于工作主要是做服務端開發,在工作中逐漸發現的使用范圍原來越廣泛。這里要注意,務必將基礎部分掌握牢靠,磨刀不誤砍柴功,只有將基礎部分掌握并建立起系統的知識體系,在后面學習衍生的其他模式才能游刃有余。 基礎鞏固:JavaScript基礎總結 使用JavaScript已經好幾年了,由于工作主要是做服務端開發,在工作中逐漸發現JavaScript的使用范圍原...
摘要:在定義函數的作用域外調用,得到的返回仍然是函數創建時所在的作用域的局部變量。這是因為所在的匿名函數的閉包中存放的是第一行的,而不是在循環中獲得的的當前值。 原文: http://pij.robinqu.me/JavaScript_Core/JavaScript_Basics/Function.html 源代碼: https://github.com/RobinQu/Pr...
摘要:之前寫過一篇天學通前端開發,內容主要講的就是前端學習路徑,今天再來寫一篇零基礎的學習路徑,希望能幫編程零基礎的前端愛好者指明方向。十框架三選一,零基礎的初學者強烈推薦,如果是后臺轉前端推薦,如果技術型前端,推薦。 之前寫過一篇26天學通前端開發,內容主要講的就是前端學習路徑,今天再來寫一篇零基礎的JavaScript學習路徑,希望能幫編程零基礎的前端愛好者指明方向。 一、開發環境和Ja...
摘要:變量定義變量使用關鍵字變量名變量名可以任意取名,但要遵循命名規則變量必須使用字母下劃線或者美元符開始。語法參數說明在消息對話框中要顯示的文本返回值值。返回值點擊確定按鈕,文本框中的內容將作為函數返回值。 簡述 本系列將持續更新Javascript基礎部分的知識,誰都想掌握高端大氣的技術,但是我覺得沒有一個扎實的基礎,我認為一切高階技術對我來講都是過眼云煙,要成為一名及格的前端工程師,必...
摘要:用和包裹的內容,稱為字符串。關系運算符用于進行比較的運算符。強制依賴于,非強制依賴于。使用場合全局環境構造函數對象的方法閉包閉包是指有權訪問另一個函數作用域中的變量的函數。所有全局對象函數以及變量均自動成為對象的成員。 1 什么是JavaScript JavaScript一種直譯式腳本語言,一種基于對象和事件驅動并具有安全性的客戶端腳本語言;也是一種廣泛應用客戶端web開發的腳本語言。...
摘要:數組創建數組數組字面量使用構造函數數組本質上是所以要判斷是不是數組,需要通過判斷。數組長度使用屬性獲取元素的個數。例如函數的對象就是這樣 原文: http://pij.robinqu.me/JavaScript_Core/JavaScript_Basics/Array.html 源代碼: https://github.com/RobinQu/Programing-In-...
閱讀 1074·2021-11-24 09:39
閱讀 1307·2021-11-18 13:18
閱讀 2425·2021-11-15 11:38
閱讀 1824·2021-09-26 09:47
閱讀 1625·2021-09-22 15:09
閱讀 1624·2021-09-03 10:29
閱讀 1510·2019-08-29 17:28
閱讀 2951·2019-08-29 16:30