js函數的那些事(一)

文章融合了《JavaScript高級程序設計》的知識,和這幾天在segmentfault上的文章的知識點。屬於整合類文章吧。segmentfault

  • 函數簡介數組

  • 函數聲明和函數表達式瀏覽器

  • this和argument閉包

  • 閉包app

函數簡介

  1. 函數其實是對象,因此函數名其實是指向函數對象的指針,那麼一個函數可能有多個名字。函數

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 ,仍然能夠正常調用。
  1. 沒有重載
    函數重載:函數重載是指在同一做用域內,能夠有一組具備相同函數名,不一樣參數列表的函數,這組函數被稱爲重載函數。js沒有重載的概念,因此若是聲明瞭兩個同名函數,則後面的函數會覆蓋前面的函數。this

  2. 做爲值得函數
    函數名自己是變量,因此能夠做爲值來使用。不只能夠像傳遞參數同樣把一個函數傳遞給另外一個函數,並且能夠將一個函數做爲另外一個函數的結果返回。設計

//把一個函數傳遞給另外一個函數的例子
    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;
    };                      //函數末尾有分號,就像聲明其餘變量時同樣。

不必定有函數名,因此有匿名函數表達式和命名函數表達式。不過,對函數命名後,一是在函數體內會表達得更清晰,二則是在調試的時候要方便不少。

區別:
函數聲明能夠在定義前調用(函數聲明提高),函數表達式不能夠(和其餘表達式同樣,使用前必需要賦值)。
函數聲明只是讓瀏覽器知道有這樣一個函數了,不會運行。瀏覽器遇到函數表達式會運行。
若是不作函數聲明的話,通常就不但願被重複調用,即很大可能就當作當即執行函數使用。
若是函數體做爲表達式的一部分,那它是函數表達式,不然爲函數聲明。

this和arguments

在函數內部有兩個特殊的對象: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引用的是函數據以執行的環境對象。

  1. 函數調用模式時,this指向window。

  2. 方法調用模式時,this指向方法所在對象。

wiondow.color="red";
var o={color:"blue"};
function sayColor(){
     alert(this.color);
}
sayColor();    //"red" 
o.sayColor=sayColor;
o.saColor();   //"blue"
  1. 構造函數模式時,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'
  1. 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'

閉包

概念:是指有權訪問另外一個函數做用域中變量的函數。
建立閉包方法:在一個函數內部建立另外一個函數。

特徵:

  1. 能夠訪問外部函數的變量。

  2. 比較佔內存。由於閉包會攜帶包含他的函數的做用域,在閉包被銷燬後外部函數的活動變量纔會被銷燬。
    (ps:關於活動變量知乎上這個問題的第二個答案寫的很是很是好!)

  3. 閉包只能取得外部函數中任何變量的最後一個值。因此要注意閉包和循環的使用:

    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變量的一個副本,就能夠返回各自不一樣的值

相關文章
相關標籤/搜索