Javascript中的對象尋找

來源:互聯網
上載者:User
文章目錄
  •   對象的分類
  •   變數的尋找
  •   屬性的尋找
  •   this的尋找
  •   總結
編輯點評:本文作者為大家介紹Javascript中的對象尋找一些問題,希望有所協助。

  近期群裡常有人提一些簡單的問題,比如發一段代碼亂七八糟的代碼,然後說裡面某個變數是什麼,比如這裡就有個很好的例子:

function fn(arg) {
alert(this.arg);
alert(this);
}
fn(123);
var o = { fn: fn };
o.fn(123);

  然後就可能有這樣的問題:

為什麼this.arg是undefined?為什麼2次調用fn的this是不一樣的?

  為此,我覺得自己作為一個雖然不成熟的前端,對於一些自己力所能及的事情,還是應該傳道授業解惑的。所以,這篇文章,計劃從非常膚淺的層面上,來解釋一下javascript中的對象尋找是如何進行的。

  注意,本篇文章只是從表象上來介紹對象尋找這一行為的過程,文章中的觀點並不全正確,甚至存在著一些謬誤,但是這也是為了讓初學者更好地理解對象尋找這一過程。相信如果說得太過抽象、深入,反而會引起一些負面效果。如果有一天,你再回過來,發現這個文章說得並不那麼正確,那麼恭喜你,那個時候的你已經可以找到正確前進的道路,這篇中的錯誤也不會再對你有任何影響。

  對象的分類

  所謂對象尋找,即在一段可執行代碼的範圍內,找到一個當前需要的對象。在javascript中,需要進行尋找的對象大致可以分為3種類型:

  • 變數尋找,如foo++;,這裡就會去尋找一個叫作foo的變數。
  • 屬性尋找,如foo.bar++;,這裡會去尋找foo這個變數下的一個叫作bar的屬性。
  • this尋找,即針對this關鍵字的處理。

  區分這3種類型的對象尋找是首先要完成的任務,你可以基於以下原則進行判斷:

  • 變數僅由變數名組成,即單獨的foo、bar等。
  • 屬性永遠由2種形式去訪問,即foo.barfoo['bar'],因此看到有“.”或“[]”即可當成是屬性尋找。
  • this就不用說了,好好的關鍵字。

  看一下這段代碼:

var foo = this;
foo.bar();

  這2行的代碼就體現了3種對象尋找,分別為:

  1. 尋找this對象,並賦值給foo變數。
  2. 查看foo變數。
  3. 尋找foo變數下的bar屬性,並將之作為一個函數進行調用。
  變數的尋找

  當確定一個對象的尋找為變數尋找後,可以按照變數尋找的規則來查看。

  變數尋找,即在範圍鏈上進行尋找,範圍鏈是javascript非常著名的2條鏈之一,以下代碼體現一個標準的範圍鏈:

var foo = 1;
function a() {
var bar = 2;
function b() {
foo = 3;
function c() {
alert(foo + ',' + bar); // 注意這一行
}
c();
}
b();
}
a();

  在c函數中,一共進行了2個變數的尋找,分別為foo和bar。

  變數的尋找可以簡單地遵守“從下向上”的原則,即:

  1. 在函數c的範圍內尋找foo和bar,顯然在c裡面並沒有foo和bar的聲明,尋找失敗。
  2. 在包含c的函數,即函數b的範圍內尋找foo和bar,可以看到b裡面只有對foo的賦值,並沒有聲明,尋找失敗。
  3. 在包括b的函數,即函數a的範圍內尋找foo和bar,可以找到bar的聲明,因此確定bar為2。
  4. 由於a不被任何函數包含,那麼就在全域範圍內尋找foo,發現有foo的聲明,因此確定foo的值為1。但是由於在函數b中,對這個foo有賦值,所以foo的值被修改為3。
  5. 完確定foo的值為3,bar的值為2,因此輸出"3,2"

  總結一下,變數的尋找是延著範圍鏈進行的,範圍鏈可以簡單地看成函數間的內含項目關聯性,被包含的函數中不存在某個變數時,在包含他的函數中尋找,直到全域範圍。

  屬性的尋找

  當確定一個對象的尋找為屬性尋找後,可以按照屬性尋找的規則來查看。

  屬性尋找,即在原型鏈上進行尋找,原型鏈是javascript雙鏈的另一條,以下可以表示出一個原型鏈:

var a = function() {};
var b = function() {};
var c = function() {};
b.prototype = new a();
c.prototype = new b();
a.prototype.foo = 1;
b.prototype.bar = 2;
c.prototype.foo = 3;
var o = new c();
alert(o.foo + ',' + o.bar); // 這一行進行尋找

  屬性尋找是一個不斷尋找prototype的過程,即:

  1. 尋找c.prototype中,有沒有顯示定義foo和和bar,發現定義了foo,其值為3。
  2. 發現c.prototype就是new b()得到的對象,那麼尋找b.prototype中,有沒有顯示定義bar,發現定義了,其值為2。
  3. 因此確定foo的值為3,bar的值為2,輸出"3,2"

  總結一下,屬性尋找是延著原型鏈進行的,原型鏈的具體知識這裡不作詳細解釋,可以另找文章進行參考。所有的對象,其原型鏈最終會是Object.prototype

  this的尋找

  this的尋找是很多人迷茫的一點,也似乎有很多人抱有this不穩定這樣的看法,實在令人無語。this的尋找可以說是3種對象尋找中最為簡單的,因為其實this對象的確定根本沒有一個“尋找”的過程。

  首先,this對象只會在一個函數中需要確定,如果是在全域域下,this永遠為Global對象,在瀏覽器中通常就是window對象。而在javascript中,函數的調用一共有4種方式:

  Function Invocation Pattern

諸如`foo()`的調用形式被稱為Function Invocation Pattern,是函數最直接的使用形式,注意這裡的foo是作為單獨的變數出現,而不是屬性。

在這種模式下,foo函數體中的this永遠為Global對象,在瀏覽器中就是window對象。

  Method Invocation Pattern

諸如`foo.bar()`的調用形式被稱為Method Invocation Pattern,注意其特點是被調用的函數作為一個對象的屬性出現,必然會有“.”或者“[]”這樣的關鍵符號。

在這種模式下,bar函數體中的this永遠為“.”或“[”前的那個對象,如上例中就一定是foo對象。

  Constructor Pattern

`new foo()`這種形式的調用被稱為Constructor Pattern,其關鍵字`new`就很能說明問題,非常容易識別。

在這種模式下,foo函數內部的this永遠是new foo()返回的對象。

  Apply Pattern

`foo.call(thisObject)`和`foo.apply(thisObject)`的形式被稱為Apply Pattern,使用了內建的`call`和`apply`函數。

在這種模式下,`call`和`apply`的第一個參數就是foo函數體內的this,如果thisObject是`null`或`undefined`,那麼會變成Global對象。

  應用以上4種方式,確定一個函數是使用什麼樣的Pattern進行調用的,就能很容易確定this是什麼。

  另外,this是永遠不會延範圍鏈或原型鏈出現一個“尋找”的過程的,只會在函數調用時就完全確認。

  總結

  對於一個對象的尋找:

  1. 確定是變數尋找、屬性尋找還是this尋找。
  2. 如果是變數尋找,則延範圍鏈找,找不到就是ReferenceError。
  3. 如果是屬性尋找,就延原型鏈找,找歪以就是undefined。
  4. 如果是this尋找,去找調用函數的代碼,根據調用的形式來確定this是什麼。
  5. 注意把一次尋找過程拆分開來,比如this.foo.bar.yahoo(),可以拆分成這樣的代碼,就能更清楚了:

    var o = this; // this尋找
    var foo = o.this; // 屬性尋找
    var bar = foo.bar; // 屬性尋找
    bar.yahoo(); // 屬性尋找,加Method Invocation Pattern

  最後,如果有一天你可以瞭解這些東西,這篇文章對你使用者也就不大了:

  • 為什麼延範圍尋找不到會有ReferenceError。
  • 其實變數也是屬性,一個特殊對象的屬性。
  • this也許不是Global,也許會是undefined。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.