1. 程式人生 > >JavaScript挑戰練習(一)-改變this指向

JavaScript挑戰練習(一)-改變this指向

一.this指向的詳解

概括:this的指向到底是指向哪裡?通常來說,只有當函式執行的時候才可以確定this指向的到底是誰,簡單的也可以這麼說:this最終指向的是那個呼叫它的物件。

常見的一般有以下幾種情況:

第一種:在一個函式中有this,但是函式沒有被上一級物件所呼叫,所以此時的this指向的是window(注意在嚴格模式下則不是),如以下程式碼:

function blue() {
    var blue = "藍源";
    console.log(this.blue);//undefind
    console.log(this);//window
}
blue();//this指向呼叫它的那個物件,在這裡相當於window

第二種:在函式中有一個this,而且該函式被上一級物件所呼叫,所以此時的this指向的是呼叫該函式的上一級物件,如以下程式碼:

var o = {
        name: "blue",
        fn: function(){
            console.log(this.name);//blue
            console.log(this);//指向o物件
        }
    }
o.fn();//此時this指向的是呼叫函式的物件o。

第三種:有一個函式中有this,函式中有多個物件,儘管這個函式是被最外層的物件呼叫,但是其中的this指向的只是它的上一級物件,如以下程式碼:

var o = {
    name: "blue",
    a: {
        fn: function(){
            console.log(this.name);//undefind,這裡有兩個物件o和a,呼叫的時候都指向上一層物件a,這裡找不到宣告的name
        }
    },
    fn1: function(){
        console.log(this.name);//blue
    }
}
o.fn1();
o.a.fn();

第四種(特殊情況):如果函式中有return,而且return返回的是一個物件,那麼呼叫時候的this指向不再是指向呼叫這個函式的例項了,而是指向這個函式返回的物件,如以下程式碼:

function fn()  
{  
    this.name = 'blue';  
    return {};  
}
var a = new fn;  
console.log(a.name); //undefined,這裡指向的是return返回的物件,是一個空物件

改變this指向的方法

第一種:使用call()

var a = {
    user:"blue",
    fn:function(){
        console.log(this.user); //blue
    }
}
var b = a.fn;
b.call(a);  //若不用call,則b()執行後this指的是Window物件

call方法除了第一個引數以外還可以新增多個引數,如下:

var a = {
    user:"blue",
    fn:function(c,d){
        console.log(this.user); //blue
        console.log(e+ee); //3
    }
}
var b = a.fn;
b.call(a,1,2);

第二種:使用apply()

var a = {
    user:"blue",
    fn:function(){
        console.log(this.user); //blue
    }
}
var b = a.fn;
b.apply(a);

apply方法和call方法很類似,也可以接收多個引數,但是第二個引數必須是陣列,如下:

var a = {
    user:"blue",
    fn:function(e,ee){
        console.log(this.user); //blue
        console.log(c+d); //11
    }
}
var b = a.fn;
b.apply(a,[10,1]);

第三種:使用bind()
bind和call,apply的使用方法有些不同,如果我們還是按照上面的方法寫程式碼,會發現一些問題,如下:

var a = {
    user:"blue",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
b.bind(a);  //程式碼沒有被列印

為什麼程式碼沒有被列印呢?這就是不同的地方所在,實際上執行bind之後返回的是一個函式,想下面這樣寫才是正確的:

var a = {
    user:"blue",
    fn:function(){
        console.log(this.user); //blue
    }
}
var b = a.fn;
var c = b.bind(a);
c();

bind()方法也可以接收多個引數,並且引數可以執行的時候再次新增,但是要注意的是,引數是按照形參的順序進行的,如下:

var a = {
    user:"blue",
    fn:function(e,d,f){
        console.log(this.user); //blue
        console.log(e,d,f); //10 1 2
    }
}
var b = a.fn;
var c = b.bind(a,10);
c(1,2);

總結:

call(),apply()以及bind()方法都可以改變this指向,只是所使用的場景有點不一樣,bind()改變後的函式想什麼時候呼叫就什麼時候呼叫,call和apply都是改變指向後立即呼叫此方法。