文章融合了《JavaScript高級程序設計》的知識,和這幾天在segmentfault上的文章的知識點。屬於整合類文章吧。segmentfault
函數簡介數組
函數聲明和函數表達式瀏覽器
this和argument閉包
閉包app
函數其實是對象,因此函數名其實是指向函數對象的指針,那麼一個函數可能有多個名字。函數
function sum(num1,num2){ retrun num1+num2; } alert(sum(10,10)); //20 var anotherSum=sum; //將sum的值賦給了anotherSum,此時它們都指向同一個函數。 alert(anotherSum(10,10)); //20 sum=null; //將sum設置爲null,使它與函數「斷絕關係」 alert(anotherSum(10,10)); //20 ,仍然能夠正常調用。
沒有重載
函數重載:函數重載是指在同一做用域內,能夠有一組具備相同函數名,不一樣參數列表的函數,這組函數被稱爲重載函數。js沒有重載的概念,因此若是聲明瞭兩個同名函數,則後面的函數會覆蓋前面的函數。this
做爲值得函數
函數名自己是變量,因此能夠做爲值來使用。不只能夠像傳遞參數同樣把一個函數傳遞給另外一個函數,並且能夠將一個函數做爲另外一個函數的結果返回。設計
//把一個函數傳遞給另外一個函數的例子 function callFunction(someFunction,someArgument){ return someFuction(someArgument); } function add10(num){ return num+10; } var result=callFunction(add10,10); //要訪問函數的指針而不執行函數的 話,要去掉函數名後的圓括號。 alert(result); //20
定義函數方法:指針
首先是函數聲明: function functionName(){}
必須有函數名。
而後是函數表達式,好比:調試
var sum = function(num1,num2){ retrun num1+num2; }; //函數末尾有分號,就像聲明其餘變量時同樣。
不必定有函數名,因此有匿名函數表達式和命名函數表達式。不過,對函數命名後,一是在函數體內會表達得更清晰,二則是在調試的時候要方便不少。
區別:
函數聲明能夠在定義前調用(函數聲明提高),函數表達式不能夠(和其餘表達式同樣,使用前必需要賦值)。
函數聲明只是讓瀏覽器知道有這樣一個函數了,不會運行。瀏覽器遇到函數表達式會運行。
若是不作函數聲明的話,通常就不但願被重複調用,即很大可能就當作當即執行函數使用。
若是函數體做爲表達式的一部分,那它是函數表達式,不然爲函數聲明。
在函數內部有兩個特殊的對象:arguments和this。
arguments是一個類數組對象,包含傳入函數的全部參數。主要做用就是保存函數參數。
arguments有一個callee屬性,該屬性是一個指針,指向擁有arguments對象的函數。
例子:
function factorial(num){ if(num<=1){ return 1; }else{ return num*factorial(num-1); } }
在函數factorial中調用了他自己,可是若是要是將函數賦值給別的變量,那就不能正常運行了。若是是下面的代碼:
function factorial(num){ if(num<=1){ return 1; }else{ return num*arguments.callee(num-1); } }
這樣,無論調用函數時使用什麼名字,均可以保證正常完成遞歸調用。
this:
this引用的是函數據以執行的環境對象。
函數調用模式時,this指向window。
方法調用模式時,this指向方法所在對象。
wiondow.color="red"; var o={color:"blue"}; function sayColor(){ alert(this.color); } sayColor(); //"red" o.sayColor=sayColor; o.saColor(); //"blue"
構造函數模式時,this指向新生成的實例。
function Aaa(name){ this.name= name; this.getName=function(){ console.log(this.name) } } var a = new Aaa('kitty'); a.getName() // 'kitty' var b = new Aaa('bobo'); b.getName() // 'bobo'
apply/call調用模式時,this指向apply/call方法中的第一個參數。
var list1 = {name:'andy'} var list2 = {name:'peter'} function d(){ console.log(this.name) } d.call(list1) // 'andy' d.call(list2) // 'peter'
概念:是指有權訪問另外一個函數做用域中變量的函數。
建立閉包方法:在一個函數內部建立另外一個函數。
特徵:
能夠訪問外部函數的變量。
比較佔內存。由於閉包會攜帶包含他的函數的做用域,在閉包被銷燬後外部函數的活動變量纔會被銷燬。
(ps:關於活動變量知乎上這個問題的第二個答案寫的很是很是好!)
閉包只能取得外部函數中任何變量的最後一個值。因此要注意閉包和循環的使用:
function foo(){ var result=new Array(); for (var i=0;i<10;i++){ result[i]=function(){ return i; }; } return result;
}
返回了一個函數數組,每一個函數都返回10。由於運行foo()函數的順序是這樣的:先運行foo()函數除了匿名函數以外的部分,完成後,再運行匿名函數。這時候for循環已經完成了,i變成了10。匿名函數引用foo()函數做用域內的活動變量i時,i已經等於10了,因此每一個函數返回的都是10。
改進:
function foo(){ var result=new Array(); for (var i=0;i<10;i++){ result[i]=function(num){ return function(){ return num; }; }(i); } return result; }
模仿塊級做用域的方法。在調用外部的匿名函數時,傳入參數i,變量i的值賦給num,在外部匿名函數內部的閉包,訪問的是numresult數組的每一個函數都有本身num變量的一個副本,就能夠返回各自不一樣的值