1. 程式人生 > >js-淺析this指向

js-淺析this指向

    在理解this的繫結過程之前,首先要理解呼叫位置:呼叫位置就是函式在程式碼中被呼叫的位置(而不是宣告的位置)。對於正常的函式呼叫,this的繫結分為以下幾種:
1. 預設繫結

    如果函式是在全域性上直接使用不帶任何修飾的函式引用進行呼叫,此時只能使用預設繫結。即在非嚴格模式下,this指向window。而如果是在嚴格模式下,則不能對全域性物件進行預設繫結,此時的this會指向undefined。如下:

  function fn(){
       console.log(this.a);
   }
   var a = 2;
   fn();

    此時console.log的結果為2
2. 隱式繫結

    隱式繫結是需要考慮函式是否是作為物件的一個屬性值進行呼叫。此時this會指向包含該函式的物件。嚴格來說,物件屬性引用鏈上只有上一層或者最後一層在呼叫位置上起作用。如下,console的列印結果為1:

var a = 42;
function fn(){
    console.log(this.a);
};
var obj1 = {
    a:1,
    fn:fn
};
obj1.fn();

    值得注意的是,隱式繫結會發生丟失繫結物件的現象。即呼叫物件不再像前文一樣直接執行物件中屬性值中的函式。而是先將該屬性值賦值給一個變數,後執行這個賦值後的變數。此時this將不再指向包含該屬性值的物件。而是決定於賦值後的變數在哪呼叫。如下:

var a  = 42;
function fn(){
    console.log(this.a)
};
var obj1 = {
    a:1,
    fn:fn
};
var b = obj1.fn;
b();

    此時console的結果為42.原因就在於b雖然是obj1.fn的引用,但是實際上它引用的是fn函式本身。因此b()此時是一個不帶任何修飾符的函式,this的指向將按照預設繫結規則進行繫結。

    除了這種情況,回撥函式進行引數傳遞時,也會發生上述情況。

  1. 顯式繫結

        通過一些方法,可以將this強制繫結到固定元素上。這種操作便是顯式繫結。常用的辦法為apply()和call()。這兩個方法的第一個引數是一個物件,是給this準備的,接著在呼叫函式的時候,將this繫結在該物件上。這兩個方法的區別在於call()的引數為一個一個的引數。而apply(),其引數為陣列形式,呼叫函式中接收時為arguments。

        顯式繫結中有一種寫法是可以解決繫結丟失的情況。即在函式呼叫的時候使用call或者apply,強制將函式的this繫結到call或apply的第一個引數上。即

function fn(){
    console.log(this.a);

}
var obj = {a:2};
var bar = function(){
    foo.call(obj);
}
bar();

    此時foo的this被強制繫結在obj上,列印結果就為2。

     在ES5中提供了一種方法,Function.prototype.bind。其z作用原理也跟上述寫法類似。

function fn(something){
    return this.a + something;
}
var obj = {
    a :2
}
var bar = fn.bind(obj);
var b = bar(3);
  1. new繫結

        在面向物件程式設計(oop)中,都會使用new來呼叫一些函式。而這些函式被稱為建構函式。建構函式是用來初始化新建立的物件。當我們使用new來呼叫一個函式時,該函式內部的this會指向一個物件。在沒有重新定義返回值的前提下,該函式返回的物件和內部指向的物件是同一個物件。

function fn(userName,age){
   //var object = new Object();
   // this = new Object;
    this.name = userName;
    this.age = age;
}
var girl = new fn('lily','23');

    上述程式碼中註釋中的程式碼只是為了演示,不具有可操作性。實際上在呼叫建構函式中,this所指向的物件是由js內部建立,而非外部程式設計可操作。