JavaScript學習總結(四)function函式部分

trigkit4發表於2016-09-16

概念

函式是由事件驅動的或者當它被呼叫時執行的可重複使用的程式碼塊。

js 支援兩種函式:一類是語言內部的函式(如eval() ),另一類是自己建立的。

在 JavaScript 函式內部宣告的變數(使用 var)是區域性變數,所以只能在函式內部訪問它。(該變數的作用域是區域性的)。

您可以在不同的函式中使用名稱相同的區域性變數,因為只有宣告過該變數的函式才能識別出該變數。

函式呼叫

有如下四種呼叫js函式的方式:

  • 作為函式
  • 作為方法
  • 作為建構函式
  • 通過call()apply()

返回函式的函式

  1. 當函式無明確返回值時,返回的值就是undefined
  2. 當函式有返回值時,返回值是什麼就返回什麼。

我們可以通過使用 return 語句實現將函式返回撥用它的地方。

在使用 return 語句時,函式會停止執行,並返回指定的值。

函式通常會返回一個唯一值,那麼這個值也可能是另一個函式:

<script type="text/javascript">
    //函式表示式
    var box = function(){
        var a=1;
        return function(){
            alert(a++)
        }
            alert(a);//永遠不會執行
    }
    alert(box());//彈出"function(){alert(a++)}"
</script>

在這裡,我們只需將返回值賦值給某個變數,然後就可以像使用一般函式那樣呼叫它了:

<script type="text/javascript">
    var box = function(){
        var a=1;
        return function(){
            alert(++a)
        }
    }
    var newFunc = box();
    newFunc();//2
</script>

如果想讓返回的函式立即執行,亦可以使用box()()來執行這段程式碼。

ECMAScript所有函式的引數都是按值傳遞的,言下之意就是引數不會按引用傳遞。

PS:如果存在按引用傳遞的話,那麼函式裡的那個變數將會是全域性變數,在外部也可以訪問。

(1)值型別:數值、布林值、null、undefined。
(2)引用型別:物件、陣列、函式。

引用型別值:指的是那些儲存在堆記憶體中的物件,意思是,變數中儲存的實際上只是一個指標,這個指標執行記憶體中的另一個位置,由該位置儲存物件;

建立匿名函式

function(){
    return ‘hi’;     //單獨的匿名函式是無法執行的,就算能執行也無法呼叫,因為沒有名字
}

這種匿名函式的用法在JQuery中非常多。直接宣告一個匿名函式,立即使用。用匿名函式的好處就是省得定義一個用一次就不用的函式,而且免了命名衝突的問題,js中沒有名稱空間的概念,因此很容易函式名字衝突,一旦命名衝突以最後宣告的為準。

javascript語言裡任何匿名函式都是屬於window物件。在定義匿名函式時候它會返回自己的記憶體地址,如果此時有個變數接收了這個記憶體地址,那麼匿名函式就能在程式裡被使用了,因為匿名函式也是在全域性執行環境構造時候定義和賦值,所以匿名函式的this指向也是window物件

(function(){
   console.log(this === window);//true
})();

通過自我執行來執行匿名函式:

//通過自我執行來執行匿名函式

<script type="text/javascript">
  (function (){         // (匿名函式)();第一圓括號放匿名函式,第二個圓括號執行
       alert('Lee');
  })();
</script>

把匿名函式自我執行的返回值賦給變數:

//把匿名函式自我執行的返回值賦給變數

<script type="text/javascript">
    var box =  (function (){           
           alert('Lee');
      })();         //彈出”Lee”;
    alert(box);   //彈出 undefined,如果寫出alert(box()),那麼只會彈出一個"Lee"   
</script>

var box= (function () {
    return 'hi';
})();
console.log(box);//hi

自我執行匿名函式的傳參:

//自我執行匿名函式的傳參

<script type="text/javascript">
    (function (age){
         alert(age);
    })(100);          //彈出100
</script>

自執行函式的三種寫法

var result = function (){
    alert(2);
}();

另一種語法也可得到同樣結果:

var result = (function () {
    console.log(2);
})();

將函式返回值分配給變數:

var result = (function () {
    return 2;
}());

js建立動態函式:

js支援建立動態函式,動態函式必須用Function物件來定義(Function是js中的一個物件,是固定不變的,規定Function物件的”F”必須大寫,當是function的時候,我們知道是定義函式的時候所使用的一個關鍵字:function funName(x,y),當是Function的時候(F大寫的時候),我們知道是js中的物件)

建立動態函式的基本格式:var 變數名 = new Function("引數1","引數2","引數n","執行語句");

看下面的一段程式碼:

<script type="text/javascript">
    var square = new Function ("x","y","var sum ; sum = x+y;return sum;");
    alert("square(2,3)的結果是:"+square(2,3));  //square(2,3)的結果是:5
</script>

square是動態建立的函式,在Function物件後面的括號裡的每一部分內容都必須是字串形式的,也就是說都必須用引號(”"或者是”)括起來

這段程式碼:

var square = new Function ("x","y","var sum ; sum = x+y;return sum;");

和下面這段程式碼:

    //函式宣告
    function square (x,y){
          var sum;
          sum = x+y;
          return sum;
     }

是一摸一樣的,只不過一個是動態函式,一個是靜態函式

我們為什麼要把程式碼分成一小段一小段的程式碼呢?,把一個字串分成了若干個獨立的字串的優點就在於我們可以通過修改其中的某些字串來隨時改變函式的作用。

回撥函式

回撥就是一個函式的呼叫過程。那麼就從理解這個呼叫過程開始吧。函式a有一個引數,這個引數是個函式b,當函式a執行完以後執行函式b。那麼這個過程就叫回撥。

其實中文也很好理解:回撥,回撥,就是回頭呼叫的意思。函式a的事先幹完,回頭再呼叫函式b。

這裡必須清楚一點:函式b是你以引數形式傳給函式a的,那麼函式b就叫回撥函式。

在jquery裡的絕大多數效果函式都涉及到callback函式。jquery效果函式

例如:

<script type="text/javascript">
        $("div").show(1000,function(){
            //callback function
        });
</script>

這裡的callback function換成例項可以是:

<script type="text/javascript">
    $("div").show(1000,function(){
        console.log("hello world")
    });
</script>

Callback實際上是,當一個函式執行完後,現執行的那個函式就是所謂的callback函式。怎麼樣?很好理解吧……

方法和函式的區別

var arr = [1,2,3,4,5]
var a =12;   // 變數:自由的
arr.a= 5;     //屬性:屬於一個物件
function show()     //函式:自由的
{
     alert(‘a’);
}
arr.fn = function()   //方法:屬於一個物件
{
     alert(‘b’);
}

其實方法就是函式,只不過方法是有所屬的物件。

我們所熟知的,將函式繫結到 click 事件

語法:

$(selector).click(function)
引數 描述
function 可選。規定當發生 click 事件時執行的函式.

這種形式在jquery中經常見到。它是將function當做該方法的引數,向該方法新增一個事件處理函式。

js全域性函式

全域性函式與內建物件的屬性或方法不是一個概念。全域性函式它不屬於任何一個內建物件。
JavaScript 中包含以下 7 個全域性函式,用於完成一些常用的功能:

escape( )、eval( )、isFinite( )、isNaN( )、parseFloat( )、
parseInt( )、unescape( )。

函式的幾個作用

作為一個類構造器使用

function Class(){}
Class.prototype={};
var item=new Class();

作為閉包使用

(function(){
    //獨立作用域
})();

作為建構函式呼叫

所謂建構函式,就是通過這個函式生成一個新物件(object)。

<script type="text/javascript"> 
        function Test(){//大寫,以區分普通函式
            this.x = 10;
        }

        var obj = new Test();
        alert(obj.x); //彈出 10;
 </script>

可以使用 new 運算子結合像 Object()Date() 和 Function() 這樣的預定義的建構函式來建立物件並對其初始化。物件導向的程式設計其強有力的特徵是定義自定義建構函式以建立指令碼中使用的自定義物件的能力。建立了自定義的建構函式,這樣就可以建立具有已定義屬性的物件。下面是自定義函式的示例(注意 this 關鍵字的使用)。

function Circle (xPoint, yPoint, radius) {
    this.x = xPoint;  // 圓心的 x 座標。
    this.y = yPoint;  // 圓心的 y 座標。
    this.r = radius;  // 圓的半徑。
}

呼叫 Circle 建構函式時,給出圓心點的值和圓的半徑(所有這些元素是完全定義一個獨特的圓物件所必需的)。結束時 Circle 物件包含三個屬性。下面是如何例示 Circle 物件。

var aCircle = new Circle(5, 11, 99);

使用構造器函式的優點是,它可以根據引數來構造不同的物件。 缺點是構造時每個例項物件都會生成重複呼叫物件的方法,造成了記憶體的浪費。

<script type="text/javascript">
    function Test(name){
        this.occupation = "coder";
        this.name = name;
        this.whoAreYou = function(){
            return "I'm " + this.name + "and I'm a " + this.occupation;
        }
    }
    var obj = new Test('trigkit4');//利用同一個構造器建立不同的物件
    var obj2 = new Test('student');

    obj.whoAreYou();//"I'm trigkit4 and I'm a corder"
    obj2.whoAreYou();//"I'm student and I'm a corder"     
 </script>

依照慣例,我們應該將構造器函式的首字母大寫,以便顯著地區別於一般的函式。

以下兩種形式的定義函式方式是等價的。

<script type="text/javascript">
    var test = function(){
        alert("Hello World");
    }
    alert(typeof(test));//output function
</script>

這裡明確定義了一個變數test,他的初始值被賦予了一個function實體

<script type="text/javascript">
    function test(){
        alert("Hello World");
    }
    alert(typeof(test));//output function
</script>

看看下面這種定義式函式形式:

<script type="text/javascript">
        function test(){
            alert("Hello World");
        };
        test();//居然輸出Hello,很奇怪不是嗎?

        function test(){
            alert("Hello");
        };
        test();//正常滴輸出了Hello
</script>

很顯然,第一個函式並沒有起到作用,很奇怪不是嗎?我們知道,javascript解析引擎並不是一行一行地執行程式碼,而是一段一段地執行程式碼。在同一段程式的分析執行中,定義式的函式語句會被優先執行,所以第一個定義的程式碼邏輯已經被第二個覆蓋了,所以兩次呼叫相同函式,只會執行第二個。

作為值的函式

函式在js中不僅是一種語法,也是一個值。也就是說可以將函式賦值給變數,儲存在物件的屬性或陣列的元素中,作為引數傳入另一個函式中。

函式的名字實際是看不見的,它僅僅是變數的名字,這個變數指代函式物件

<script type="text/javascript">
     function square(x,y){
         return x*y;
     }
     var s = square; //s和square指代同一個函式
     square(2,3);//6
     s(2,4);//8
</script>

除了可以將函式賦值給變數,同樣可以將函式賦值給物件的屬性,當函式作為物件的屬性呼叫時,函式就稱為方法

<script type="text/javascript">
     var obj = {square:function(x,y){ //物件直接量
         return x*y;
     }};
     var ect = obj.square(2,3);
</script>

prototype屬性

每一個函式都包含prototype屬性,這個屬性指向一個物件的引用,這個物件稱為原型物件。

詳見:javascript學習總結(五)原型和原型鏈

call()和apply()

apply()函式有兩個引數:第一個引數是上下文,第二個引數是引數組成的陣列。如果上下文是null,則使用全域性物件代替。例如:

function.apply(this,[1,2,3])

call()的第一個引數是上下文,後續是例項傳入的引數序列,例如:

function.call(this,1,2,3);

高階函式

這裡的高階函式可不是高數裡的那個高階函式,所謂高階函式就是操作函式的函式,它接收一個或多個函式作為引數,並返回新函式

引數arguments

當函式被呼叫時,會得到一個免費奉送的引數陣列,那就是arguments陣列。通過它,函式可以訪問所有它被呼叫時傳遞給他的引數列表。這使得編寫一個無需指定引數個數的函式成為可能。

<script type="text/javascript">
    var sum = function(){
        var i ,sum =0;
        for(i = 0;i<arguments.length;i+=1){
            sum+=arguments[i];
        }
        return sum;
    };
    document.writeln(sum(4,5,23,13,35,46,-10));//116
</script>

ECMAScript中的引數在內部是用一個陣列來表示的,函式接收到的始終都是這個陣列,而不關心陣列中包含哪些引數

function add(num1,num2){
    num = num1 + num2;
    return num;
}

var result = 12,count = 20;
alert(add(result,count));//32;命名的引數只提供便利,解析器不會驗證命名引數

實際上,arguments並不是一個真正的陣列,它只是一個類陣列的物件,它擁有一個length屬性,但他缺少所有陣列的方法。另外,arguments物件的長度是由傳入的引數個數決定的,而不是由定義函式時的命名引數的個數決定的

函式在定義或者宣告的時候,所有的引數都是形參,因此,我們可以根據實際情況來命名引數,函式也只有在被呼叫時才會傳入實參。而每個函式在被呼叫時都會自動取得兩個特殊變數:this 和 arguments

函式的遞迴

函式的遞迴,即一個函式在通過名字呼叫自身的情況下構成的:

通過使用argument.callee代替函式名:

//arguments.callee是一個指向正在執行的函式的指標
<script>
    function factorial(num){
        if(num<=1){
            return 1;
        }else{
            return num*arguments.callee(num-1);
        }
    }
</script>

思維導圖

最後附上一張前輩總結的思維導圖:

JavaScript學習系列文章目錄

相關文章