1. 程式人生 > 實用技巧 >JS中bind,call,apply的用法與實現

JS中bind,call,apply的用法與實現

JS中bind,call,apply的用法與實現

春招衝刺01.16日 - 01

1. 什麼是bind,call,apply

  
bind,call,apply是JavaScript中Function物件自帶的三個方法,用於改變函式體內部的 this 指向,也就是函式呼叫時的上下文(context)。

bind,call,apply三者都可以利用後續引數傳參。其中bind不會立即呼叫,而是返回對應的繫結函式,其內的this指向為建立它時傳入bind的 第一個引數,而傳入bind的第二個及以後的引數作為 原函式的引數 來呼叫原函式。

bind(thisArg[, arg1[, arg2[, ...]]])

apply、call則是立即呼叫,改變的this指向他們的第一個引數,apply的第二個引數是一個引數陣列,call的第二個及其以後的引數都是數組裡面的元素。

call ( thisArg, arg1, arg2, ... )
apply ( thisArg ,[argArray] )

2. call的應用與實現

在call的語法call ( thisArg, arg1, arg2, ... )中,thisArg的傳遞情況有:

  • null,undefined或不傳 此時指向window
  • 傳遞另一個函式B的函式名,函式中的this指向B的引用
  • 傳遞字串、數值或布林型別等基礎型別,函式中的this指向其對應的包裝物件,如 String、Number、Boolean
  • 傳遞一個物件,函式中的this指向這個物件

常用方法:

function pChain (){
        this.name="pChainRoot";
        this.nameprint=function(){
            console.log('列印的名字是',this.name);
        }
    }

var newname={name:"PChainChild"};
var PChain=new pChain();
PChain.nameprint.call(newname);  //PChainChild
PChain.nameprint();              //pChainRoot

模擬實現:

Function.prototype.myCall = function (thisArg,...args){
        
        //thisArg為呼叫mycall方法的函式的this指向
        var thisArg = thisArg || window
        
        //將this賦給thisArg的fn屬性
        //此處this指代呼叫myCall的function
        thisArg.fn = this;  
        
        var result = thisArg.fn(args);
        delete thisArg.fn;
        return result;

    }
    PChain.nameprint.myCall(newname);  //pChainChild

3. apply的應用與實現

apply與call的作用是一樣的,不過二者接收引數的方法不一樣,apply要求將call的剩餘引數儲存在一個數組中。
當明確知道引數數量時用 call ,而不確定的時候用 apply,並將把引數 push 進陣列傳遞進去,使函式內部也通過 arguments 這個陣列來遍歷所有的引數。
常用方法:

function pChain2 (name1,name2){
    this.name1=name1;
    this.name2=name2;
    this.nameprint=function(){
        console.log('列印的名字是',this.name1+'與'+this.name2);
    }
}
function pChainChild2 (){
        this.name1="PChainChild1";
        this.name2="PChainChild2";
        var PChain2 = new pChain2("pChainRoot1","pChainPoot2");

        //call的傳參方法
        PChain2.nameprint.call(this,name1,name2);  //PChainChild1與PChainChild2

        PChain2.nameprint();      //pChainRoot1與pChainPoot2
        
        //apply的傳參方法
        PChain2.nameprint.apply(this,[name1,name2]);  //PChainChild1與PChainChild2
}

pChainChild2();

模擬實現:

Function.prototype.myApply = function(thisArg){
        //thisArg為呼叫mycall方法的函式的this指向
        var thisArg = thisArg || window
        
        //將this賦給thisArg的fn屬性
        //此處this指代呼叫myCall的function
        thisArg.fn = this;  
        
        var result;
        if (arguments[1]) {
	        result = thisArg.fn(arguments[1]);
        } else {
        	result = thisArg.fn();
        }
        delete thisArg.fn;
        return result;
    }

4. bind的應用與實現

bind是在es5中擴充套件的方法(IE6,7,8不支援),但是返回值是函式。

常用方法:

var bar= function () {
    console.log(this.x);
}
var foo = {
    x:3
}

bar(); //undefined

bar.bind (foo) (); //3

要注意的是多次 bind() 是無效的。

var foo2 = {
    x:5
}
bar.bind (foo).bind (foo2) (); //3

模擬實現:

Function.prototype.myBind=function(){
        var _this = this;
        var context = [].shift.call(arguments);// 儲存需要繫結的this上下文
        var args = [].slice.call(arguments); //剩下引數轉為陣列
        
        return function(){
            _this.apply(context, [].concat.call(args, [].slice.call(arguments)));
        }
    }