【JavaScript】深入理解call,以及與apply、bind的區別


一、call

call有兩個妙用

     1、繼承(我前面的文章有提到用call實現call繼承,有興趣可以看下。https://www.cnblogs.com/pengshengguang/p/10547624.html

     2、修改函數運行時this的指向(今天要說的)

// 代碼段一
var obj = {name: 'psg'};
function fn(num1, num2) {
    console.log(num1+num2);
    console.log(this)  
}
// 1、call里面,第一個參數就會說要變成this的對象
fn(100, 200); //this指向window, num1=100, num2=200
fn.call(100, 200); //this指向100, num1=200, num2=undefined
fn.call(obj, 100, 200); //this指向obj,  num1=100, num2=200

// 2、在非嚴格模式下,call里面,第一個參數如果是空、null、undefined,會導致this指向window
fn.call(); //this指向window

// 3、在嚴格模式下,call里面,傳誰this就是誰,不傳,this就是undefined
fn.call(); //this指向undefined
fn.call(null); //this指向null
fn.call(undefined); //this指向undefined

 

二、apply

     1、apply和call方法的作用是一模一樣的,都是用來改變方法中this關鍵字並且將方法執行,而且在嚴格模式、非嚴格模式下對於第一個參數是null / undefined這種情況的規律也是一樣的。

     2、跟call唯一的的區別就是語法的區別:

//call傳遞參數是用逗號分隔,一個一個傳進去
fn.call(obj, arg1,arg2,arg3.....)
//apply傳遞參數是用一個數組傳的
fn.apply(obj, [arg1,arg2,arg3....])

 

三、bind

     1、這個方法在IE6-IE8下不兼容。

     2、與apply、call類似,都是用來改變this指向,但是bind體現了js的預處理思想。

          ->預處理:實現把fn的this改變成我們想要的結果,並且把對象的參數也准備好了,以后要用到了,直接執行即可。

var obj = {name: 'psg'};
function fn(num1, num2) {
    console.log(num1+num2);
    console.log(this);
}
fn.call(obj, 100, 200);
fn.bind(obj, 100, 200);  // 只是改變了fn中的this為obj,並且給fn傳遞了兩個參數值,但是此時並沒有給fn這個函數執行。
// 但是,執行bind會有一個返回值,這個返回值myFn就是我們把fn的this改變后的那個結果!!!

//那么,如何讓fn這個函數執行呢,下面的寫法就行解決方法
var myFn = fn.bind(obj, 100, 200);
myFn();

 

四、深入理解call

  4.1 如果我們要理解call,我們首先要知道call是怎樣被執行的,涉及到了原型鏈查找機制。

//例如,現在有一個函數fn,我們想改變fn中this的指向,因此我們可以
fn.call(obj);
//上面的代碼,其實是首先通過fnl的原型鏈,找到Function.ptototype中的call方法,然后執行call方法,cal方法中的this,就是fn

  4.2 偽代碼模擬實現call方法

 

//偽代碼
Function.prototype.myCall = function(context) {
    //->1、讓fn中的this關鍵字變成context
    this = eval(this.toString().replace("this", context));
    //->2、讓fn執行
    this();  
}  

 

  

 

  4.3 經典面試題

// 練習一
function fn1() {console.log(1);}
function fn2() {console.log(2);}
fn1.call(fn2); // ->1    
// 原理:首先fn1通過原型鏈機制找到Function.prototype上的call方法,並且讓call方法執行
// 此時call這個方法中的this就是fn1,在call方法執行過程中,讓fn1中this關鍵字變成fn2,然后讓fn1執行

fn1.call.call(fn2); // ->2
// 原理首先fn1通過原型鏈機制找到Function.prototype上的call方法,然后再讓call方法通過原型找到call方法
// Function.prototype原型上的call(因為fn.call這個東西也是個函數數據類型),在第二次找到call時,讓call方法執行,此時
// 的this是fn1.call。

  end

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM