2016-05-15 39 views
-1

我知道局部變量dosent在測試時工作,但我不理解這個概念。爲什麼「this」有效並且局部變量不能?澄清將是偉大的爲什麼我必須使用這個和避免局部變量! 代碼:在一個類的構造函數中爲什麼是「this required」?爲什麼不能使用局部變量?

function Person(job, married) { 
    var employ = job; 
    var status = married; 
    } 
    var ray = new Person("student", true); 
    console.log(ray); 
+0

只要您離開它們定義的範圍,局部變量就會被銷燬。 – zerkms

+2

您可以使用局部變量,但它們只能由構造函數中的代碼訪問。它們不是創建對象的屬性。如果你想分配對象的屬性,你必須引用對象本身'this.someProp = someValue'。有一些設計模式在構造函數中分配內聯方法,並且這些方法可以訪問構造函數中的局部變量,但這些變量不能直接從構造函數外部訪問。 – jfriend00

+0

哦,屬性本質上是全球性的?這就是你爲什麼使用這個? –

回答

1

您可以在構造函數中使用局部變量,但它們不會自動成爲對象的實例變量。相反,你使用它們的方式,它們只是暫時的局部變量,就像任何函數定義中的局部變量一樣。

當你這樣做:

function Person(job, married) { 
    var employ = job; 
    var status = married; 
} 
var ray = new Person("student", true); 

這裏是正在發生的事情:

  1. 你定義一個名爲Person功能。
  2. 在該函數中,您可以定義兩個名爲employstatus的局部變量。
  3. 這些是函數內的正常局部變量。它們只對該函數內的代碼可見。這些可能對某些事情有用,但它們不可用於該功能之外的任何代碼。它們不適用於您的對象的原型方法,它們不適用於該函數之外的其他代碼。事實上,如果沒有某種引用關閉的參考,它們的生命週期就會有限,並且只要Person函數完成執行,它們就會消失並垃圾回收。
  4. 所以,如果你打算創建對象的成員變量的C++等價物,這並沒有完成。這些變量僅用於Person()函數的持續時間,然後被處理並且沒有持久存在。
  5. 然後,當您執行var ray = new Person("student", true);時,會發生以下情況。
  6. new會導致系統創建一個新對象,將值this設置爲指向該新對象,然後使用兩個參數調用構造函數Person
  7. 然後,您的代碼將創建兩個您分配兩個參數的局部變量。
  8. Person()函數然後完成執行,並且處理兩個局部變量,因爲它們被定義的範圍已完成並且被垃圾收集。
  9. 然後,您將新創建的對象分配給變量ray。這確實是一個新對象,但它沒有自定義實例數據,因爲沒有任何內容以持久方式存儲。
  10. 如果您接着執行console.log(ray),則只會看到一個空對象,而不包含默認對象實例所具有的實例數據。您的自定義數據沒有存儲在任何地方,因此現在已經消失。

如果您打算將這兩個參數保存在持續作爲對象的實例數據的某個位置,則您有幾個選擇。更傳統的選擇是使它們成爲公共可訪問的對象屬性。你會是這樣做的:

function Person(job, married) { 
    this.employ = job; 
    this.status = married; 
} 

由於this指向新創建的對象,這段代碼jobmarried參數分配給新創建的對象的屬性。這些屬性可以通過對象上的其他方法或通過構造函數之外的任何代碼來訪問,如下所示:

var ray = new Person("student", true); 
console.log(ray.employ); // "student" 
console.log(ray.status); // true 

這些屬性是可公開訪問的。


還有一些有趣的事情,你可以與那些局部變量,可以讓他們持續,創建對象後使用做。要做到這一點,你必須創建一個閉包。我認爲閉包是一個函數作用域,當函數完成執行時通常會被丟棄,但由於環境的原因,函數作用域中仍然存在實時引用,所以當函數完成執行時,垃圾收集器不會丟棄函數作用域就像使用C++這種純粹基於堆棧的語言一樣。相反,它在創建對象後仍然存在並可以通過代碼訪問。下面是一個例子:

function Person(job, married) { 
    var employ = job; 
    var status = married; 

    this.getEmploy = function() { 
     return employ; 
    } 

    this.getStatus = function() { 
     return status; 
    } 
} 
var ray = new Person("student", true); 
console.log(ray.getEmploy()); // "student" 
console.log(ray.getStatus()); // true 

這裏是在構造函數內賦值的函數創建了一個閉包。私人局部變量employstatus在Person函數的範圍內仍然是私有的。但是,由於getEmploygetStatus屬性現在已公開公開,並且可以在將來某個時間調用,並且這些函數引用employstatus變量,垃圾收集器意識到它無法垃圾收集employstatus變量,因此它們堅持這個新創建的Person對象的生命週期。

使用其他面嚮對象語言(如C++)的熟悉術語,employstatus局部變量爲您提供了一些私有實例變量的功能。有些人稱這爲黑客,以填補Javascript無法直接提供的功能。但是,我不認爲它是一種破解。該語言提供閉包作爲一個非常有用的功能,可用於多種方式,這只是一種使用閉包創建私有實例數據的好處的好處。

只有公開分配的性質getEmploygetStatus可以被外界訪問,但是通過調用它們,我們可以訪問私有變量employstatus。如果我們在這個新模型中使用console.log(ray),我們仍然不會在那裏看到employstatus,因爲就控制檯而言,它們仍然不是ray對象的屬性。但是,由於關閉,它們可以通過ray對象上的方法唯一訪問。

此外,因爲一個新的封閉每次創建我們稱之爲Person構造,這些employstatus變量是唯一與Person對象的每個新的實例相關聯。他們的行爲和工作就像對象的私人成員一樣。

對於這種類型的結構和一些更多的解釋更多的例子,看到這個經典的論述:http://javascript.crockford.com/private.html

爲什麼「這個」工作和局部變量不?

除非創建某種持久閉包,否則局部變量是暫時的。只有包含函數正在執行,它們才持續存在,然後進行垃圾回收。僅僅因爲它們是在你用作構造函數的函數內部聲明的,並不會使它們變得特別。它們只是局部變量,除了局部變量之外沒有什麼魔力。

在一個類的構造函數爲什麼是「this required」? 澄清將是偉大的爲什麼我必須使用這個,並避免當地 變量!

如果你想屬性分配給您的對象,它是this指向在構造你的對象所以唯一的辦法分配給你的對象的屬性是引用該對象爲this.someProperty = xxxx。這就是語言的工作原理。在Javascript中的所有屬性引用都需要一個對象作爲訪問的第一部分。並且,在構造函數中,新創建的對象的引用是this。這就是語言的設計。

那些來自其他一些面向對象的語言的人可能會聲明一個類的實例變量,然後只是自己使用這個名稱,解釋器會知道它是一個實例變量名稱,而不是變量名稱。在其他一些語言中可能是這樣。在Javascript中這不是真的。所有屬性引用(無論是在構造函數中,某些方法中還是從外部作爲對象的屬性訪問)都必須使用一個對象作爲引用的基礎。並且,在構造函數和方法內部,該基數是this的值。所以,this.someProperty是你如何引用當前實例的屬性。

+0

非常感謝你!只是爲了確保你在getemploy函數中添加了「this」,因爲函數也是一個變量,所以你想讓它公開,所以你使用「this」,是否正確? –

+0

@MatthewFrancis - 我不會像你這樣說。對象屬性可以包含任何類型的值,數字,字符串,函數引用等等。在這種情況下,它包含一個函數引用,使其成爲您可以調用的對象的方法。 – jfriend00

0

認爲它是這樣的:

類基本上是一個對象,對不對?那麼,當你聲明Person的新實例時,你會說「讓我們用屬性x,y和z創建一個新對象。」使用「this」可以稍後訪問該實例的屬性,而局部變量不會被視爲您的對象的屬性。

0

當函數被調用爲構造函數(使用關鍵字new)時,將創建一個新對象(實例對象),在函數原型屬性的對象值上創建原型,並使用其值this設置值構造函數到剛剛創建的新實例對象。

構造函數代碼可以在this(實例對象)上設置屬性和方法,這是構造函數調用的返回值(...除非構造函數顯式返回其他一些對象)。

如果在構造函數中定義的變量被構造函數返回後繼續存在的嵌套函數訪問,它們將不會被垃圾回收,因爲它們仍然可以被訪問。如果在構造函數返回後它們不可訪問,則它們基本上被丟棄並可用於垃圾回收。

對象創建是JavaScript行爲的基礎:嘗試查找並閱讀有關構造函數的使用。

通過搜索「JavaScript中的閉包」,可以找到關於外部函數退出後嵌套函數範圍內變量保留的更多信息。

相關問題