《Web 前端面試指南》二、JavaScript 的 Bind 函數進階

使用 Bind() 設置方法中 this 對象

//<button>獲取隨機的人</button>​
//<input type="text">​
​
​var user = {
    data:[
        {name:"張三", age:37},
        {name:"李四", age:43}
    ],
    clickHandler:function (event) {
        var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // 隨機獲取 0 或者 1
        // 從數組中取出值,賦值到 Input 文本框內
        $ ("input").val (this.data[randomNum].name + " " + this.data[randomNum].age);
    }​
}

​// 綁定事件
$ ("button").click (user.clickHandler);

當點擊的時候,會報錯,由於 clickHandler 方法中的 this 指向的是 button 元素。javascript

爲了解決這個問題,咱們可使用 bind 方法。
使用以下代碼:java

$ ("button").click (user.clickHandler.bind (user));

代替以前:數組

$ ("button").click (user.clickHandler);

可是,在 IE9 如下和 Firefox 3.x 的瀏覽器中,是不支持 Bind 方法的,因此能夠考慮加入以下方法。瀏覽器

// 判斷是否支持 Bind 方法
if (!Function.prototype.bind) {
    Function.prototype.bind = function (oThis) {
        if (typeof this !== "function") {
            throw new TypeError (" Function.prototype.bind - 綁定錯誤");
        }
        var aArgs = Array.prototype.slice.call (arguments, 1),
                fToBind = this,
                fNOP = function () {
                },
                fBound = function () {
                    return fToBind.apply (this instanceof fNOP && oThis
                            ? this​
                            : oThis,
                            aArgs.concat (Array.prototype.slice.call (arguments)));
                };
        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP ();
        return fBound;
    };
}

咱們繼續咱們的例子,考慮以下代碼:app

// 全局變量
var data = [
    {name:"王五", age:12},
    {name:"陳六", age:14}
]

var user = {
    // 局部變量
    data:[
        {name:"張三", age:37},
        {name:"李四", age:43}
    ],
    showData:function (event) {
        var randomNum = ((Math.random () * 2 | 0) + 1) - 1;
        console.log (this.data[randomNum].name + " " + this.data[randomNum].age);
    }
}
var showDataVar = user.showData;
showDataVar (); // 王五 12 (這裏說明是從 全局變量而不是局部變量中取數據)​

當執行 showDataVar() 時,this 指向的是全局變量,而不是局部變量。這是由於 showDataVar() 是做爲全局函數執行的,它是綁定的是全局做用域,也就是瀏覽器的 window 對象。dom

一樣,咱們能夠經過使用 bind 方法指定 this 的值來解決這個問題:函數

// 把 showData 綁定到 user 對象
var showDataVar = user.showData.bind (user);
​
// 如今咱們獲得了 user 的值
showDataVar (); // 張三 43​

Bind() 能夠實現借調方法 (Borrow Methods)

咱們知道在 JavaScript 中咱們能夠傳遞函數,返回函數和借調函數。Bind() 方法會使借調函數變地很是簡單易用。
以下代碼:this

// 這裏有個 cars 對象,它裏面沒有任何函數。
var cars = {
   data:[
       {name:"黎明", age:14},
       {name:"劉德華", age:2}
   ]
}
​
// 咱們能夠從上面例子中借調 user 對象中 showData () 函數。
// 咱們綁定 user.showData 函數處理 cars 對象。
cars.showData = user.showData.bind (cars);
cars.showData (); // 黎明 14

這樣寫的代碼有個問題,就是會在 cars 對象中,新加一個函數(showData),這可能不是咱們的本意,由於可能 cars 對象中此前已經有了​一個叫 showData 的屬性或者函數了。咱們不想意外覆蓋它。在下文中會說明,最好的借調方式是使用 Apply 或者 Call。url

JavaScript 中的 Bind() 能夠實現函數柯里化(Function Currying)

柯里化:是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,而且返回接受餘下的參數且返回結果的新函數的技術。百度百科的定義prototype

首先,看如下代碼,是個有三個參數的方法 greet():

function greet (gender, age, name) {
    // 若是性別爲男,使用 "先生", 不然使用 "女士"。​
    var salutation = gender === "male" ? "先生" : "女士";
    ​
    if (age > 25) {
        return "你好," + name + salutation + "。";
    }
    else {
        return "你好," + name + "。";
    }
}

接下來,咱們使用 bind() 來進行函數柯里化()。

// 由於咱們不想使用 this 關鍵字,因此第一個參數咱們傳遞 null。
var greetAnAdultMale = greet.bind (null, "male", 45);
​
greetAnAdultMale ("李連杰"); // "你好,李連杰先生。"​
​
var greetAYoungster = greet.bind (null, "", 16);
greetAYoungster ("成龍"); // "你好, 成龍。"​
greetAYoungster ("李小龍"); // "你好,李小龍。"

當咱們使用 bind() 進行柯里化的時候,除了最後一個外,全部的參數都被預設置好了。

相關文章
相關標籤/搜索