1. 程式人生 > >函式內this指向的不同場景,以及如何改變this的指向(bind,call,apply)

函式內this指向的不同場景,以及如何改變this的指向(bind,call,apply)

一. 對於接觸前端不太久的時候,相信會有個讓大家都感到頭疼的問題,沒錯那就是關於 this 的指向問題。我在剛接觸不久的時候也有過這樣一段時間,不過大家也不用擔心,相信大家只要把這篇部落格認真研究一遍,一定會對 this 會有一些新的認識。

函式的呼叫方式決定了 this 的指向不同:

 1. 普通函式呼叫,此時 this 指向 window

    function fn() {
       console.log(this);   // window
     }
     fn();  //  window.fn(),此處預設省略window

2. 建構函式呼叫, 此時 this 指向 例項物件

 function Person(age, name) {
         this.age = age;
         this.name = name
         console.log(this)  // 此處 this 
分別指向 Person 的例項物件 p1 p2 } var p1 = new Person(18, 'zs') var p2 = new Person(18, 'ww')

3. 物件方法呼叫, 此時 this 指向 該方法所屬的物件

 var obj = {
       fn: function () {
         console.log(this); // obj
       }
     }
    obj.fn();

4.通過事件繫結的方法, 此時 this 指向 繫結事件的物件 

 btn.onclick = function() {
       console.log(this); // btn
     }

5. 定時器函式, 此時 this 指向 window

 setInterval(function () {
       console.log(this); // window
     }, 1000);

以上五個方面 就是對函式內部 this 指向的基本整理

關於this 的終極總結 : 函式內部的 this 是由呼叫時確定其指向。

二. 接下來一起來看一下如何使用bind,call,apply改變 this的指向,以及他們各自一些小的應用

1.bind()會建立一個新的函式(稱為繫結函式),與被呼叫函式有相同的函式體,當目標函式被呼叫時this的值繫結到 bind()的第一個引數上,如下面demo 此時this

指向 物件o

 語法: fn.bind(thisArg[, arg1[, arg2[, ...]]])   

 引數:thisArg 當繫結函式被呼叫時,該引數會作為原函式執行時的 this 指向。當使用new 操作符呼叫繫結函式時,該引數無效。

arg1,arg2.. 當繫結函式被呼叫時,這些引數將置於實參之前傳遞給被繫結的方法

返回值:返回由指定的this值和初始化引數改造的原函式拷貝。

var obj = {name: 'obj'};
    obj.fn = function () {
        console.log(this)
    };
    var o = {name: 'o'};
    var rel = obj.fn.bind(o);
    rel();  // 等價 obj.fn.bind(o)() 

2.call()  方法呼叫一個函式, 其具有一個指定的this 值和分別地提供的引數(引數的列表)。

 語法: fn.call(thisArg[, arg1[, arg2[, ...]]])   

 引數:thisArg 該引數會作為函式執行時的this指向。(如果指定了 null 或者 undefined 則內部 this 指向 window)

               arg1,arg2..    指定的引數列表

 var obj = {name: 'obj'};
    obj.fn = function () {
        console.log(this)
    };
    var o = {name: 'o'};
    obj.fn.call(o)   //  與bind的區別是,call直接呼叫函式

3.apply() 方法呼叫一個函式, 其具有一個指定的 this 值,以及作為一個數組(或類似陣列的物件)提供的引數。

 語法: fn.apply(thisArg[argArray])   

 引數:thisArg 

         argArray

apply() 與call()非常相似,不同之處在於提供引數的方式,apply()使用引數陣列,而不是引數列表

 var obj = {name: 'obj'};
    obj.fn = function (a, b) {
        a = b;
        console.log(this)
    };
    var o = {name: 'o'};
    obj.fn.apply(o, [1, 3])

相信已經對 bind,call,apply 有一定的認識了,接下來看幾個案例

案例一 :

 需求: 呼叫該物件 fun 方法時 改變其 this指向  打印出 obj 的 name

 var obj =  {
            name : 'zs',
            fun: function() {
                setInterval(function() {
                    console.log(this.name);
                }.bind(this),1000);      // 利用 bind 不呼叫函式特性此處this指向 obj
            }
        };
         obj.fun();

案例二:

 var obj = {
            0:10,
            1:20,
            2:30,
            length:3
        };
        Array.prototype.push.call(obj,40);   
        console.dir(obj);  

案例三:

   var arr = [4,5,6,8,11,44];
        Math.max.apply(Math, arr); // 可以利用apply 第二個引數是陣列。

有什麼不足或者建議歡迎大家評論區探討。謝謝