標籤:
一、函數定義
函式宣告語句聲明了一個變數,並把一個函數對象賦值給它。定義函數運算式沒有聲明變數。
如果一個函數定義運算式包含名稱,函數的局部範圍會包含一個綁定到函數對象的名稱。函數的名稱成為函數內部的局部變數。
函式宣告語句“被提前”到外部指令碼或外部函數範圍頂部,可以在它定義前出現的代碼調用。但運算式定義的函數不能。
二、函數調用1.函數調用
如果函數運算式是一個屬性訪問運算式,即該函數是一個對象的屬性或數組的一個元素,則它是方法調用運算式
2.方法調用
o.m();
對象o成為調用上下文,函數體可以使用this引用該讀寫
當方法傳回值是一個對象,它還可以再調用它的方法。當方法不需要傳回值,最好返回this。
this是關鍵字,不允許給this賦值。this沒有範圍的限制,嵌套的函數不會從調用它的函數繼承this。如果嵌套函數作為方法調用,其this值指向調用它的對象。如果嵌套函數作為函數調用,其this值不少全域對象(非strict 模式下)就是undefined(strict 模式下)。如果想訪問外部函數的this值,需要將this儲存在一個變數裡,這個變數和內建函式都在同一個範圍。通常用變數self儲存this。
var o = { m: function() { var self = this; console.log(this === o); //true f(); function f() { //嵌套函數f() console.log(this === o); //false console.log(self === o); //true } }};
3.建構函式調用
如果建構函式沒有形參,可以省略實參列表和圓括弧。
建構函式調用建立新的對象,對象繼承自建構函式的prototype屬性,將這兒對象當做其調用上下文。
4.間接調用
call() apply()
作為命名空間的函數
定義一個函數作為臨時的命名空間,其中定義的變數不會汙染到全域命名空間。
// 因為想下面第一個聲明的function可以在後面加一個括弧()就可以自己執行了,比如foo(),// 因為foo僅僅是function() { /* code */ }這個運算式的一個引用 var foo = function(){ /* code */ } ()
//解析器解析全域的function或者function內部function關鍵字的時候,預設是認為function聲明,而不是function運算式,
//如果你不顯示告訴編譯器,它預設會聲明成一個缺少名字的function,並且拋出一個語法錯誤資訊,因為function聲明需要一個名字。
function(){ /* code */ }(); // SyntaxError: Unexpected token
我們只需要用大括弧將代碼的代碼全部括住就行了,因為JavaScript裡括弧()裡面不能包含語句。
所以在這一點上,解析器在解析function關鍵字的時候,會將相應的代碼解析成function運算式,而不是function聲明。
// 下面2個括弧()都會立即執行(function () { /* code */ } ()); // 推薦使用這個(function () { /* code */ })(); // 但是這個也是可以用的
定義一個匿名函數,在單個運算式中調用它。
(function() { //代碼}());
function之前的左圓括弧是必須的,如果不寫會將function姐希望函式宣告語句。使用圓括弧被解析為函數定義運算式
閉包
函數對象可以通過範圍鏈相互關聯,函數體內部的變數都可以儲存在函數範圍內,這種特性成為閉包。
//返回 function f() {return a;}var a = ‘global‘;function check() { var a = ‘local‘; function f() {return a;} return f;}check()
閉包可以捕捉到局部變數(和參數),並一直儲存。
//check()只返回函數內嵌套的一個函數對象,而不是直接返回結果。
//返回 local scopevar a = ‘global‘;function check() { var a = ‘local‘; function f() {return a;} return f;}check()()
每次調用javascript函數時,都會為之建立一個新對象來儲存局部變數,把這個對象添加到範圍鏈。當函數返回時,從範圍鏈中將這個綁定變數的對象刪除。如果不存在嵌套的函數,也沒有其他引用指向這個綁定對象,它會被當做垃圾處理。 如果定義了嵌套函數,每個嵌套的函數都各自對應一個範圍鏈,並且這個範圍鏈指向一個變數綁定對象。
如果這個函數定義了嵌套的函數並將它作為傳回值返回或儲存在某處的屬性裡,這時就會有一個外部參考指向這個嵌套的函數,它和它指向的變數綁定對象都不會被當做記憶體回收。
//定義了一個立即調用的函數,函數的傳回值賦值給a//外部函數返回後,其他代碼無法訪問count變數var uniqueInteger = (function() { var count = 0; return function() {return count++}; }());uniqueInteger //函數對象uniqueInteger() //0uniqueInteger()() //1
//返回一個總是返回v的函數function constfuncs(v) { return function() { return v;}; }var funcs = [];for (var i = 0; i < 10; i++) funcs[i] = constfuncs(i);alert(funcs[5]()) //5//這些閉包都在同一個函數調用定義,可以共用變數ifunction constfuncs() { var funcs = []; for (var i = 0; i < 10; i++) funcs[i] = function() { return i; }; return funcs;}var funcs = constfuncs();alert(funcs[5]()) //10
函數屬性、方法和建構函式
length屬性
prototype屬性
call() apply() 方法
bind()方法 將函數綁定到某個對象
toString()方法
Function()建構函式
可以傳入任意數量的字串參數,最後一個參數的文本是函數體。
不需要傳入函數名
函數體代碼的編譯總在頂層函數執行,可以認為是在全域範圍執行的eval()
var scope = "global";function constructFunction() { var scope = "local"; return new Function("return scope");}//返回global,因為通過Function()建構函式返回的函數使用的不是局部範圍constructFunction()()
《Javascript權威指南》函數