1. 程式人生 > 其它 >bind,call,以及apply的理解與使用

bind,call,以及apply的理解與使用

技術標籤:javascript

bind的理解:

Function.prototype.bind()

官方原話/作用:
bind() 方法建立一個新的函式,在 bind() 被呼叫時,
這個新函式的 this 被指定為 bind() 的第一個引數,而其餘引數將作為新函式的引數,
供呼叫時使用。

返回值:返回一個原函式的"拷貝",並擁有指定的 this 值和初始引數。

   //例子
   function demoBind(x){
     console.log('我是第一個demoBind===>',this,x.into);
   }
   demoBind
({into:"未繫結bind"}); //window,未繫結bind console.log('-------------------->分割線'); /* 利用bind建立一個“新的函式” const newBind = demoBind.bind("這個新函式的 this 被指定為 bind() 的第一個引數","其餘引數將作為新函式的引數,供呼叫時使用") # 這裡也就是說bind的第一個引數將作為新函式的this指向,而bind的其他引數將是新函式的其他引數、 下方例子(拷貝場景): */
const newBind = demoBind.bind({_this:1},{into:"繫結bind"}); newBind(); //{_this:1},繫結bind /* 應用場景:需要讓this指定自己需要物件的this就可以使用bind方法 */ var application = { b: function() { console.log('b的this指向不出意外是application===>',this); // {c: "hello", b: ƒ} const
func =function(){ /* 在不使用bind的情況下,函式在獨立呼叫時,函式內部的this是指向window的 console.log(this); // window */ /* 假設我在func裡面需要得到c定義的hello,那麼在這裡就能使用bind來指定this */ console.log(this); //使用了bind之後這裡的this就指向了{c: "hello", b: ƒ} }.bind(this) //bind的第一個引數將作為新函式的this指向,我這裡傳入b的this指向也就是application,所以func的this也就指向了application func(); }, c: 'hello' } application.b(); /* - 引用與拷貝的區別 引用:二者的引用是同一個物件,並沒有創建出一個新的物件 因為是同一個物件的引用,所以兩者改一個,另一個物件的值也隨之改變 拷貝:簡單來講就是會建立一個新的物件,改變新的物件的值並不會影響到原物件 */

call的理解:

Function.prototype.call()

作用:
call() 可以允許為不同的物件分配和呼叫屬於一個物件的函式/方法/屬性。
call() 提供新的 this 值給當前呼叫的函式/方法。你可以使用 call 來實現繼承:寫一個方法,然後 讓另外一個新的物件來繼承它(而不是在新物件中再寫一次這個方法)。

官方原話:
call() 方法使用一個指定的 this 值和單獨給出的一個或多個引數來呼叫一個函式

語法引數:function.call(thisArg, arg1, arg2, …)

thisArg:
可選的。在 function 函式執行時使用的 this 值。
請注意,this可能不是該方法看到的實際值:如果這個函式處於非嚴格模式下,
則指定為 null 或 undefined 時會自動替換為指向全域性物件,原始值會被包裝。

arg1, arg2, …:
指定的引數列表。

返回值: 得到使用呼叫者提供的 this 值和引數呼叫該函式的返回值。若該方法沒有返回值,則返回 undefined

    //'use strict';  開啟嚴格模式
    //例子
    function Person(...x) {
      console.log(this,x);
    }
    Person("張三","張三"); //window,["張三","張三"]


    //在thisArg指定為null或undefined的情況下會自動替換為指向全域性物件也就是window
    const _call = Person.call(null,"張三","張三","張三")  //window,["張三","張三","張三"]
    //person函式沒有返回值,_call為undefined
    console.log(_call); 
      
      //應用例子
	 //呼叫父建構函式的 call 方法來實現繼承
     //假設這是一個父物件
     function Product(name, price) {
        console.log('Product====>',this); //Food
        this.name = name;
        this.price = price;
      }

      function Food(name, price) {
        /*
          這裡把this分配到Product裡面之後,Product的this就指向了Food
        */
        Product.call(this, name, price); //call() 可以允許為不同的物件分配和呼叫屬於一個物件的函式/方法/屬性。
        this.category = 'food';
        this.log =function(){
          console.log(this);//Food {name: "feta", price: 5, category: "food", log: ƒ}
          console.log(name,price,this.category); //feta 5 food
        }
      }

      function Toy(name, price) {
        Product.call(this, name, price);
        this.category = 'toy';
      }

      var cheese = new Food('feta', 5);
      cheese.log();
      var fun = new Toy('robot', 40);

      /*
        要知道如果這個函式處於非嚴格模式下,
        則指定為 null 或 undefined 時會自動替換為指向全域性物件,原始值會被包裝。
        但是在嚴格模式下,this 的值將會是 undefined

        例子:
      */
      var sData = 'Wisen';

      function display() {
        console.log(this);// undefined
        console.log('sData value is %s ', this.sData);  //報錯
      }

      display.call(); 

apply的理解:

Function.prototype.apply()

作用:
可以用 apply 將陣列各項新增到另一個數組

官方原話:
apply() 方法呼叫一個具有給定this值的函式,以及以“一個數組(或類陣列物件)”的形式提供的引數

thisArg:
同call()的thisArg
argsArray:
可選的。一個數組或者類陣列物件,其中的陣列元素將作為單獨的引數傳給 func 函式。
如果該引數的值為 null 或 undefined,則表示不需要傳入任何引數。
從ECMAScript 5 開始可以使用類陣列物件。

返回值:呼叫有指定this值和引數的函式的結果 (大概意思同call()方法)

function PersonApply(...x) {
      console.log(this,x);
    }
    PersonApply("張三","張三"); //window,["張三","張三"]


    //在thisArg指定為null或undefined的情況下會自動替換為指向全域性物件也就是window
    const _apply = PersonApply.apply({a:1},["張三","張三","張三"])//{a:1},["張三","張三","張三"]
    
    console.log(_apply); //沒有返回值  返回undefined

    //作用同call
    //用 apply 將陣列各項新增到另一個數組
   /*
     官方例子原話:
      我們可以使用push將元素追加到陣列中。由於push接受可變數量的引數,所以也可以一次追加多個元素。

	  但是,如果push的引數是陣列,它會將該陣列作為單個元素新增,而不是將這個陣列內的每個元素新增進去,
      因此我們最終會得到一個數組內的陣列。如果不想這樣呢?concat符合我們的需求,
      但它並不是將元素新增到現有陣列,而是建立並返回一個新陣列。
      然而我們需要將元素追加到現有陣列......那麼怎麼做好?難道要寫一個迴圈嗎?別當然不是!

      apply正派上用場
      由於push可以一次追加多個元素然後在利用apply的特點:
      apply()會將引數陣列轉換為一個接一個的引數方式傳遞給方法
      類似一個迴圈,在迴圈apply的陣列引數,把它拆成一個一個的item
   */
    var array = ['a', 'b'];
    var elements = [0, 1, 2];
    //array作為this的指向
    array.push.apply(array, elements);
    console.info(array); // ["a", "b", 0, 1, 2]
    /*
      concat也是可以將兩個數組合併成為一個數組,但是它並不是將元素新增到現有陣列,而是建立並返回一個新陣列
    */

總結:

1,call方法和apply方法是函式的引用
2,bind方法是函式的拷貝

3this指向:
    - call,bind,apply的第一個引數都是this的指向,並且第一個引數如果為null或undefined的話都會預設指向全域性物件

4,引數:
   - call()方法以及bind()接受的是引數列表,而apply()方法接受的是一個引數陣列

5,返回值:
   - bind返回一個原函式的"拷貝",並擁有指定的 this 值和初始引數
   - call方法和apply方法得到使用呼叫者提供的 this 值和引數呼叫該函式的返回值。若該方法沒有返回值,則返回 undefined

6,call()和apply()會直接呼叫函式,bind()不會

7,apply()會將引數陣列轉換為一個接一個的引數方式傳遞給方法
   /*
     類似一個迴圈,在迴圈apply的陣列引數,把它拆成一個一個的item
   */