call、apply、bind

剛開始寫技術筆記的時候,很淺顯的寫了一篇this的指向問題,如今看起來不能說錯誤百出,但也確實是沒什麼技術水平。今天分享本身對於call、apply、bind新的認識,並手寫一個本身的call、apply、bind。面試

三個方法的語法大致同樣:數組

fnction fn() {}閉包

fn.call(thisArg, arg1, arg2, ...)app

fn.apply(thisArg, [arg1,arg2,...])函數

fn.bind(thisArg, arg1, arg2, ...)this

call和bind的參數同樣,apply的參數是一個數組(a開頭,Array),call和apply返回的是fn執行的結果,bind返回的是fn的拷貝並指定this值和參數(bind不執行,須要調用)。spa

thisArg是可選的,fn的this指向是thisArg對象。prototype

非嚴格模式thisArg指定爲null、undefined,fn的this指向就是window:3d

function fn() {code

console.log(this);//window

}

fn.call()

嚴格模式fn的this指向是undefined:

"use strict"

function fn() {

console.log(this);//undefined

}

fn.call()

若是thisArg是數字、字符串、布爾值,this指向原始值的對象:

function fn() {

console.log(this);//String||Number||Boolean

}

fn.call('' || 5 || true)

call、apply和bind是掛在Function對象上的方法,只有函數才能調用。

說真的,這三個方法開發業務的時候並不經常使用,有用也是用來裝一裝,面面試。三個方法最主要的就是藉助別人的方法,減小重複代碼,節省內存。好比fn1方法和fn2方法,fn2須要用到fn1的方法,這時候直接用fn1的方法而不是本身聲明一個方法。bind方法比較不同,bind返回的是一個函數,因此還能夠用來作閉包等。

好比求一個數組的最大最小值:

var arr = [5, 6, 2, 8, 1];

console.log(Math.max.apply(Math, arr));//8

console.log(Math.min.apply(Math, arr));//1

實現一個call::

Function.prototype.myCall = function (context) {

if(context === undefined || context === null){

context = window;
複製代碼

}else{

context = Object(context);
複製代碼

};

context.fn = this;

let result = context.fn([...arguments].slice(1));

delete context.fn;

return result;

};

這邊須要注意的一個就是context,不能context = context || window;由於這樣會把原始數值都綁定到window,可是上面也說了,String是綁定String的。還有就是直接context.fn也是不夠嚴謹,可使用symbol就絕對不會衝突,只能說fn這個須要用特殊的不會命名衝突的去實現,考慮兼容的話symbol好像也不是很是合適。

實現一個apply:

Function.prototype.myApply = function (context) {

if(context === undefined || context === null){

context = window;
複製代碼

}else{

context = Object(context);
複製代碼

};

context.fn = this;

let result;

if(arguments[1] instanceof Array){

result = context.fn(...arguments[1]);
複製代碼

}else{

result = context.fn();
複製代碼

};

delete context.fn;

return result;

};

跟call差很少,就是一個參數的判斷不同,其餘的跟call的注意點同樣。

實現一個bind:

Function.prototype.mybind = function (context) {

let that = this;

if(context === undefined || context === null){

context = window;
複製代碼

}else{

context = Object(context);
複製代碼

};

let args = [...arguments].slice(1);

return function Fn() {

if(this instanceof Fn){

  return new that(...args, ...arguments)

}else{

  return that.apply(context, args.concat(...arguments));

}
複製代碼

}

}

由於bind返回的是一個函數,因此思路是同樣的,不一樣的是須要判斷,bind以後是不是直接new這個函數,若是是new,那麼this就是這個構造函數。

function Fn() {

console.log(this);//Fn

}

new Fn();

相關文章
相關標籤/搜索