函數 - Javascript語法基礎 - Javascript核心

原文: http://pij.robinqu.me/JavaScript_Core/JavaScript_Basics/Function.htmljavascript

源代碼: https://github.com/RobinQu/Programing-In-Javascript/blob/master/chapters/JavaScript_Core/JavaScript_Basics/Function.mdhtml

本文存在批註,但該網站的Markdown編輯器不支持,因此沒法正常展現,請到原文參考。java

函數

Javascript中,要記住函數是first-class citizen。node

定義

  • 函數聲明語句git

    function plus(x ,y) {
    
    }
  • 函數定義表達式github

    var plus = function (x, y) {
    
    }

函數調用

  • 做爲函數調用數組

    function a(){};
    a();
  • 做爲方法調用瀏覽器

    a={};
    a.x = function(){};
    a.x();
  • 經過call和apply間接調用函數(改變this)閉包

call 和 apply帶有多個參數,call和apply把當前函數的this指向第一個參數給定的函數或對象中,並傳遞其他全部的參數做爲當前函數的參數。app

var O = function () {
    this.foo  = 'hello';
    this.hello = function () {
        return 'world';
    }
};

var fn = function () {
    console.log('call', this);
};

var o = new O();

fn.call(o);//此時fn的this指向o

call和apply的不一樣之處,在於call傳遞的參數是做爲arguments依次傳入的,例如

fn.call(o, 1, 2, 3);
而apply傳遞的參數是以一個數組的方式傳入的,例如
fn.apply(o, [1, 2, 3]);

參數

當傳入參數少於函數聲明的參數時,留空的參數的值是undefined

Javascript容許傳入參數的個數大於聲明時制定的參數個數。能夠用arguments來訪問這些參數

function f(){
    var i;
    for( i = 0; i < arguments.length ; i++) {
        console.log(arguments[i]);
    }
}

f(1,2,3,4,5,6);

函數經過取得arguments的長度獲得傳入參數的個數,使用一個循環獲取每個參數。

arguments還有兩個屬性,calleecaller
callee表示正在執行的function對象,
caller表示調用當前function的function

例如

function f(){
    console.log(arguments.callee);//[Function: f]
    console.log(arguments.callee.caller);[Function: g]
    var i;
    for( i = 0; i < arguments.length ; i++) {
        console.log(arguments[i]);
    }
}

function g(){
    f(1,2,3,4,5,6);
}

g();

callee 的重要用法之一是在匿名函數中實現遞歸

var result = function (x) {
    if (x <= 1) return 1;
    return x * arguments.callee(x - 1);
}(3);

console.log(result);

上例使用了一個匿名函數和callee實現了一個階乘。

做爲值的函數

javascript中的函數能夠做爲值來傳遞

function square(x) {
    return x * x;
}

var s = square;
s(4);

做爲命名空間的函數

(function() {

}());

閉包

Javascript函數對象的內部狀態不只包含着函數的代碼邏輯,還引用當前的做用域鏈。函數對象經過做用域鏈相互關聯起來,函數體內部變量包含在函數做用域內,這就叫閉包。

例如

var scope = 'global scope';
function checkscope() {
    var scope = 'local scope';
    function f() { 
        return scope;
    }
    return f;
}

checkscope()();

這段checkscope聲明瞭一個局部變量,定義了一個函數f,函數f返回了這個局部變量的值,最後返回了這個函數f。在定義函數f的做用域外調用f,獲得的返回仍然是函數f建立時所在的做用域的局部變量scope。

又例如

var counter = (function() {
    var count = 0;
    return function () {
        return count++ ;
    }
}());

代碼定義了一個當即執行函數並返回給counter,這個函數定義了一個局部變量count,返回了一個子函數,該子函數每次調用,都會吧count加一併返回。

閉包的注意事項

觀察下面的示例:

var add_the_handlers = function (nodes) {
    var i;
        for (i = 0; i < nodes.length; i += 1) {
            nodes[i].onclick = function (e) {
                alert(i);
            };
        }
};

這個函數指望的結果,是在運行的時候爲每一個node在onclick的時候alert出各自的序號,可是實際運行的結果卻不一樣:全部的node在單擊的時候alert出來的數字老是同一個。

這是由於alert所在的匿名函數的閉包中存放的i是第一行的i,而不是在循環中得到的i的當前值。

因此若是但願達到預期結果,應該在循環中建立多個閉包,在閉包中存放當前循環的i的值:

var add_the_handlers = function (nodes) {
    var i;
        for (i = 0; i < nodes.length; i += 1) {
            nodes[i].onclick = function (i) {
                return function(e){
                    alert(e);
                };
            }(i);
        }
};

這裏使用一個當即執行函數並傳遞當前的i的值,返回一個新生成的函數。在這個新生成的函數的閉包中就保存了當前的i的值。

函數中的this對象

在一個對象中的this始終引用當前對象,可是在函數中,特別是在閉包中,this有一些特殊的行爲。

函數中的this對象始終綁定在函數運行時的上下文環境上。因此在普通模式下調用一個全局函數,this始終指向window(客戶端),在嚴格模式下調用一個全局函數,this始終是undefined

示例

var name = "The Window";
var object = {
    name: "My Object",
    getNameFunc: function () {
        return function () {
            return this.name;
        };
    },
    getName : function () {
        return this.name;
    }
};

console.log(object.getNameFunc()());
console.log(object.getName());

getNameFunction()返回了一個匿名函數,這個匿名函數在調用的時候,上下文是window(瀏覽器中),因此在瀏覽器中輸出的是the Window

而getName()調用的時候上下文是object,因此成功輸出object的name

其實以上代碼中
object.getNameFunc()()
等效於
var fnc = object.getNameFunc();//這時候的fnc已經脫離了object對象
fnc();

因此若是想要getNameFunction()正確返回Object的Name,須要在返回的匿名函數的閉包中保存在函數聲明時的this,

getNameFunc: function () {
        var that = this;
        return function () {
            return that.name;
        };
    },

這樣就能夠了。。

函數柯里化

函數柯里化是指,把接受多個參數的函數轉換成接受一個單一參數的函數,而且返回接受餘下的參數並且返回結果的新函數的技術。

示例

var add1 = add.curry(1);
console.log(add1(2));

其中,add是接受兩個參數的函數,add調用了curry返回一個只接受一個參數的新函數,以後調用add1便等效於調用add(1, 2);

javascript並不原生支持curry,能夠用prototype來模擬

Function.prototype.curry = function () {
    var slice = Array.prototype.slice,
        args = slice.apply(arguments),
        that = this;
    return function () {
        return that.apply(null, args.concat(slice.apply(arguments)));
    };
};


function add(n1, n2) {
    return n1 + n2;
}

var add1 = add.curry(1);
console.log(add1(2));

curry建立了一個新函數,在新函數的閉包中保存了原先傳遞的參數。

函數的屬性和方法

  • length 函數的length表示函數實參的數量,是隻讀的
  • prototype 指向一個該函數的原型對象的引用
  • toString 返回一個字符串
相關文章
相關標籤/搜索