call,apply,bind的用法以及區別

2022-08-28 19:24:10 字數 4979 閱讀 7369

方法呼叫模式:

當乙個函式被儲存為物件的乙個方法時,如果呼叫表示式包含乙個提取屬性的動作,那麼它就是被當做乙個方法來呼叫,此時的this被繫結到這個物件。

var a = 1

var obj1 =

}obj1.fn()//2

此時的this是指obj1這個物件,obj1.fn()實際上是obj1.fn.call(obj1),事實上誰呼叫這個函式,this就是誰。補充一下,dom物件繫結事件也屬於方法呼叫模式,因此它繫結的this就是事件源dom物件。如:

document.addeventlistener('click', function(e), 200);

}, false);

函式呼叫模式

就是普通函式的呼叫,此時的this被繫結到window

最普通的函式呼叫

function fn1()

fn1()

函式巢狀

function fn1()

fn2()

}fn1()

把函式賦值之後再呼叫

var a = 1

var obj1 =

}var fn1 = obj1.fn

fn1()//1

obj1.fn是乙個函式function(),此時fn1就是不帶任何修飾的函式呼叫,function().call(undefined),按理說列印出來的 this 應該就是 undefined 了吧,但是瀏覽器裡有一條規則:

如果你傳的 context 是 null 或者 undefined,那麼 window 物件就是預設的 context(嚴格模式下預設 context 是 undefined)

因此上面的this繫結的就是window,它也被稱為隱性繫結。

如果你希望列印出2,可以修改fn1()為fn1.call(obj1),顯示地繫結this為obj1

**函式

var a = 1

function f1(fn)

f1(f2)

function f2()

改寫**如下:

var a = 1

function f1())()

console.log(a)//1

}f1()

仍舊是最普通的函式呼叫,f1.call(undefined),this指向window,列印出的是全域性的a。

藉此,我們終於可以解釋為什麼settimeout總是丟失this了,因為它也就是乙個**函式而已。

settimeout(function() 

fn()

}, 0);

構造器呼叫模式:

new乙個函式時,背地裡會建立乙個連線到prototype成員的新物件,同時this會被繫結到那個新物件上

function person(name,age)

}var dot = new person('dot',2)

dot.sayage()//2

call

call 方法第乙個引數是要繫結給this的值,後面傳入的是乙個引數列表。當第乙個引數為null、undefined的時候,預設指向window。

var arr = [1, 2, 3, 89, 46]

var max = math.max.call(null, arr[0], arr[1], arr[2], arr[3], arr[4])//89

可以這麼理解:

obj1.fn() 

obj1.fn.call(obj1);

fn1()

fn1.call(null)

f1(f2)

f1.call(null,f2)

看乙個例子:

var obj = 

function getname(firstname, lastname)

getname.call(obj, 'dot', 'dolby')//my name is: dot dolby

var arr = [1,2,3,89,46]
可以這麼理解:

obj1.fn() 

fn1()

f1(f2)

看乙個例子:

var obj = 

function getname(firstname, lastname)

可以看到,obj 是作為函式上下文的物件,函式 getname 中 this 指向了 obj 這個物件。引數 firstname 和 lastname 是放在陣列中傳入 getname 函式。

var person1  = function () 

var person2 = function ()

person1.call(this);

}var person = new person2();

person.getname(); // dot

從上面我們看到,person2 例項化出來的物件 person 通過 getname 方法拿到了 person1 中的 name。因為在 person2 中,person1.call(this) 的作用就是使用 person1 物件代替 this 物件,那麼 person2 就有了 person1 中的所有屬性和方法了,相當於 person2 繼承了 person1 的屬性和方法。

bind

和call很相似,第乙個引數是this的指向,從第二個引數開始是接收的引數列表。區別在於bind方法返回值是函式以及bind接收的引數列表的使用。

bind返回值是函式

var obj = 

function printname()

var dot = printname.bind(obj)

console.log(dot) // function ()

dot() // dot

bind 方法不會立即執行,而是返回乙個改變了上下文 this 後的函式。而原函式 printname 中的 this 並沒有被改變,依舊指向全域性物件 window。

引數的使用

function fn(a, b, c) 

var fn1 = fn.bind(null, 'dot');

fn('a', 'b', 'c'); // a b c

fn1('a', 'b', 'c'); // dot a b

fn1('b', 'c'); // dot b c

fn.call(null, 'dot'); // dot undefined undefined

call 是把第二個及以後的引數作為 fn 方法的實參傳進去,而 fn1 方法的實參實則是在 bind 中引數的基礎上再往後排。

有時候我們也用bind方法實現函式珂里化,以下是乙個簡單的示例:

var add = function(x) ;

};var increment = add(1);

var addten = add(10);

increment(2);

// 3

addten(2);

// 12

在低版本瀏覽器沒有 bind 方法,我們也可以自己實現乙個。

if (!function.prototype.bind) 

}}

應用場景

求陣列中的最大和最小值

var arr = [1,2,3,89,46]
將類陣列轉化為陣列

var truearr = array.prototype.slice.call(arraylike)
陣列追加

var arr1 = [1,2,3];

var arr2 = [4,5,6];

// arr1 [1, 2, 3, 4, 5, 6]

// arr2 [4,5,6]

判斷變數型別

function isarray(obj)

isarray() // true

isarray('dot') // false

function person(name,age)

}function female()

var dot = new female('dot',2)

使用 log ** console.log

function log()

// 當然也有更方便的 var log = console.log()

總結箭頭函式體內的 this 物件, 就是定義時所在的物件, 而不是使用時所在的物件;所以不需要類似於var _this = this這種醜陋的寫法

箭頭函式不可以當作建構函式,也就是說不可以使用 new 命令, 否則會丟擲乙個錯誤

箭頭函式不可以使用 arguments 物件,,該物件在函式體內不存在. 如果要用, 可以用 rest 引數代替

不可以使用 yield 命令, 因此箭頭函式不能用作 generator 函式,什麼是generator函式可自行查閱資料,推薦閱讀阮一峰generator 函式的含義與用法,generator 函式的非同步應用

聊聊call apply bind的故事

實際上它們真正的樣子是這樣的 它們幾個的作用都是改變this的指向。bind 與另外兩個的區別則是前者改變this,不立即呼叫函式 而後者改變this,立即呼叫函式。以下例子在非嚴格模式下,注釋的是各個情況this的指向 let test test.foo test.foo.call null,1,...

寫給新人的call apply bind

語法 1 fun.call thisarg arg1 arg2 thisarg fun函式執行時指定的this值,可能的值為 例如 123 456functiona functionb a.call b functionb 經常會看到這種使用情況 123 45function list list 1...

理解 call, apply, bind 的用法

call 方法使用乙個指定的this值和單獨給出的乙個或多個引數來呼叫乙個函式。function list list 1,2,3,4,5 1 陣列的所有方法都是掛在array的prototype上的,如圖 而類陣列物件本身是沒有這些方法的,當然也無法呼叫 那麼想在一些物件上呼叫這個物件本身沒有的方法...