天天看點

JavaScript 中call、apply、bind學習JavaScript 中call、apply、bind學習

JavaScript 中call、apply、bind學習

Array.find(function(v,i,arr),thisArgs}

數組執行個體的find方法,用于找出第一個符合條件的數組成員。它的參數是一個回調函數,所有數組成員依次執行該回調函數,直到找出第一個傳回值為true的成員,然後傳回該成員。如果沒有符合條件的成員,則傳回undefined。

- v:數組值

- i:索引

- arr:目前數組

- thisArgs:fn函數中this指向

Array.filter(fn(v,i),thisArgs)

過濾,傳回數組中的滿足回調函數中指定的條件的元素。

Array.map(fn(v,i),thisArgs)

對數組的每個元素調用定義的回調函數并傳回包含結果的數組。

Array.every(fn(v,i),thisArgs)

數組的所有成員是否滿足指定的測試

Array.some(fn(v,i),thisArgs)

隻要數組的一個值滿足指定的測試,就傳回true

- thisArgs: fn方法中this指向,如果是object類型正常指向,如果是string類型,會按fn中的i去截取string中對位的位置的字元

bind,call,apply

  • var slice = Function.prototype.call.bind(Array.prototype.slice);
var Dog=function(){
    this.name="汪星人";
    this.shout=function(){
        alert(this.name);
    }
};

var Cat=function(){
    this.name="喵星人";
};
var dog=new Dog();
var cat=new Cat();
dog.shout();

dog.shout.call(cat); // 執行dog.shout方法,指定cat的環境
cat.shout();
           

call函數

  • 簡單的了解:把a對象的方法應用到b對象上(a裡如果有this,會指向b);
  • 比較

call 和 apply 的功能是一緻的,兩者細微的差别在于 call 以參數表來接受被調用函

數的參數,而 apply 以數組來接受被調用函數的參數。call 和 apply 的文法分别是:

func.call(thisArg[, arg1[, arg2[, ...]]])
func.apply(thisArg[, argsArray])
           

其中,func 是函數的引用,thisArg 是 func 被調用時的上下文對象,arg1、arg2 或

argsArray 是傳入 func 的參數。我們以下面一段代碼為例介紹 call 的工作機制:

var someuser = {
    name: 'monoplasty',
    display: function(words) {
        console.log(this.name + ' says ' + words);
    }
};

var foo = {
    name: 'foobar'
};

someuser.display.call(foo, 'hello'); // 輸出 foobar says hello
           

用 Node.js 運作這段代碼,我們可以看到控制台輸出了 foobar。

someuser.display

是被調用的函數,它通過 call 将上下文改變為 foo 對象,是以在函數體内通路

this.name

時,實際上通路的是

foo.name

,因而輸出了foobar。

bind函數

call函數和apply函數功能一樣,差別是第二個參數形式不一樣,call傳遞多個參數,任意形式(傳入參數和函數所接受參數一一對應),apply第二個參數必須是數組形式,如a.call(b,2,3); ==> a.apply(b,[2,3]);

可以使用 bind 方法來永久地綁定函數的上下文,使其無論被誰調用,上

下文都是固定的。bind 文法如下:

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

其中 func 是待綁定函數,thisArg 是改變的上下文對象,arg1、arg2 是綁定的參數表。

bind 方法傳回值是上下文為

thisArg

func

通過下面例子可以幫你了解 bind 的使用方法:

var someuser = {
    name: 'monoplasty',
    func: function() {
        console.log(this.name);
    }
};

var foo = {
    name: 'foobar'
};

foo.func = someuser.func;
foo.func(); // 輸出 foobar

foo.func1 = someuser.func.bind(someuser);
foo.func1(); // 輸出 monoplasty

func = someuser.func.bind(foo);
func(); // 輸出 foobar

func2 = func;
func2(); // 輸出 foobar
           

上面代碼直接将

foo.func

指派為

someuser.func

,調用

foo.func()

時,this指針為

foo

,是以輸出結果是

foobar

foo.func1

使用了 bind 方法,将

someuser

作為this指針綁定到

someuser.func

,調用 foo.func1() 時,this指針為

someuser

,是以輸出結果是

monoplasty

。全局函數

func

同樣使用了 bind 方法,将

foo

作為 this 指針綁定到

someuser.func

,調用

func()

時,this 指針為

foo

,是以輸出結果是

foobar

。而

func2

直接将綁定過的

func

指派過來,與

func

行為完全相同。

使用 bind 綁定參數表

bind 方法還有一個重要的功能:綁定參數表,如下例所示。

var person = {
    name: 'monoplasty',
    says: function(act, obj) {
        console.log(this.name + ' ' + act + ' ' + obj);
    }
};

person.says('loves', 'javascript'); // 輸出 monoplasty loves javascript

monoplastyLoves = person.says.bind(person, 'loves');
monoplastyLoves('you'); // 輸出 monoplasty loves you
           

可以看到,

monoplastyLoves

将 this 指針綁定到了

person

,并将第一個參數綁定到

loves

,之後在調用

monoplastyLoves

的時候,隻需傳入第二個參數。這個特性可以用于建立一個函數的“捷徑”,之後我們可以通過這個“捷徑”調用,以便在代碼多處調用時省略重複輸入相同的參數。

了解 bind

盡管 bind 很優美,還是有一些令人迷惑的地方,例如下面的代碼:

var someuser = {
    name: 'monoplasty',
    func: function () {
        console.log(this.name);
    }
};

var foo = {
    name: 'foobar'
};

func = someuser.func.bind(foo);
func(); // 輸出 foobar

func2 = func.bind(someuser);
func2(); // 輸出 foobar
           

全局函數

func

通過

someuser.func.bind

将this指針綁定到了

foo

,調用

func()

輸出了

foobar

。我們試圖将

func2

指派為已綁定的

func

重新通過

bind

将this指針綁定到

someuser

的結果,而調用

func2

時卻發現輸出值仍為

foobar

,即 this 指針還是停留在

foo

對象上,這是為什麼呢?要想解釋這個現象,我們必須了解 bind 方法的原理。

讓我們看一個 bind 方法的簡化版本(不支援綁定參數表):

someuser.func.bind = function(self) {
    return this.call(self);
};
           

假設上面函數是

someuser.func

bind

方法的實作,函數體内 this 指向的是

someuser.func

,因為函數也是對象,是以

this.call(self)

的作用就是以

self

作為this指針調用

someuser.func

/* 将func = someuser.func.bind(foo)展開: */ 
func = function() {
    return someuser.func.call(foo);
};

 // 再将func2 = func.bind(someuser)展開:
func2 = function() {
    return func.call(someuser);
};
           

從上面展開過程我們可以看出,

func2

實際上是以

someuser

作為

func

的this指針調用了

func

,而

func

根本沒有使用 this 指針,是以兩次 bind 是沒有效果的。

繼續閱讀