您可以在構造函數中使用局部變量,但它們不會自動成爲對象的實例變量。相反,你使用它們的方式,它們只是暫時的局部變量,就像任何函數定義中的局部變量一樣。
當你這樣做:
function Person(job, married) {
var employ = job;
var status = married;
}
var ray = new Person("student", true);
這裏是正在發生的事情:
- 你定義一個名爲
Person
功能。
- 在該函數中,您可以定義兩個名爲
employ
和status
的局部變量。
- 這些是函數內的正常局部變量。它們只對該函數內的代碼可見。這些可能對某些事情有用,但它們不可用於該功能之外的任何代碼。它們不適用於您的對象的原型方法,它們不適用於該函數之外的其他代碼。事實上,如果沒有某種引用關閉的參考,它們的生命週期就會有限,並且只要
Person
函數完成執行,它們就會消失並垃圾回收。
- 所以,如果你打算創建對象的成員變量的C++等價物,這並沒有完成。這些變量僅用於
Person()
函數的持續時間,然後被處理並且沒有持久存在。
- 然後,當您執行
var ray = new Person("student", true);
時,會發生以下情況。
new
會導致系統創建一個新對象,將值this
設置爲指向該新對象,然後使用兩個參數調用構造函數Person
。
- 然後,您的代碼將創建兩個您分配兩個參數的局部變量。
Person()
函數然後完成執行,並且處理兩個局部變量,因爲它們被定義的範圍已完成並且被垃圾收集。
- 然後,您將新創建的對象分配給變量
ray
。這確實是一個新對象,但它沒有自定義實例數據,因爲沒有任何內容以持久方式存儲。
- 如果您接着執行
console.log(ray)
,則只會看到一個空對象,而不包含默認對象實例所具有的實例數據。您的自定義數據沒有存儲在任何地方,因此現在已經消失。
如果您打算將這兩個參數保存在持續作爲對象的實例數據的某個位置,則您有幾個選擇。更傳統的選擇是使它們成爲公共可訪問的對象屬性。你會是這樣做的:
function Person(job, married) {
this.employ = job;
this.status = married;
}
由於this
指向新創建的對象,這段代碼job
和married
參數分配給新創建的對象的屬性。這些屬性可以通過對象上的其他方法或通過構造函數之外的任何代碼來訪問,如下所示:
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
這裏是在構造函數內賦值的函數創建了一個閉包。私人局部變量employ
和status
在Person函數的範圍內仍然是私有的。但是,由於getEmploy
和getStatus
屬性現在已公開公開,並且可以在將來某個時間調用,並且這些函數引用employ
和status
變量,垃圾收集器意識到它無法垃圾收集employ
和status
變量,因此它們堅持這個新創建的Person
對象的生命週期。
使用其他面嚮對象語言(如C++)的熟悉術語,employ
和status
局部變量爲您提供了一些私有實例變量的功能。有些人稱這爲黑客,以填補Javascript無法直接提供的功能。但是,我不認爲它是一種破解。該語言提供閉包作爲一個非常有用的功能,可用於多種方式,這只是一種使用閉包創建私有實例數據的好處的好處。
只有公開分配的性質getEmploy
和getStatus
可以被外界訪問,但是通過調用它們,我們可以訪問私有變量employ
和status
。如果我們在這個新模型中使用console.log(ray)
,我們仍然不會在那裏看到employ
和status
,因爲就控制檯而言,它們仍然不是ray
對象的屬性。但是,由於關閉,它們可以通過ray
對象上的方法唯一訪問。
此外,因爲一個新的封閉每次創建我們稱之爲Person
構造,這些employ
和status
變量是唯一與Person
對象的每個新的實例相關聯。他們的行爲和工作就像對象的私人成員一樣。
對於這種類型的結構和一些更多的解釋更多的例子,看到這個經典的論述:http://javascript.crockford.com/private.html
爲什麼「這個」工作和局部變量不?
除非創建某種持久閉包,否則局部變量是暫時的。只有包含函數正在執行,它們才持續存在,然後進行垃圾回收。僅僅因爲它們是在你用作構造函數的函數內部聲明的,並不會使它們變得特別。它們只是局部變量,除了局部變量之外沒有什麼魔力。
在一個類的構造函數爲什麼是「this required」? 澄清將是偉大的爲什麼我必須使用這個,並避免當地 變量!
如果你想屬性分配給您的對象,它是this
指向在構造你的對象所以唯一的辦法分配給你的對象的屬性是引用該對象爲this.someProperty = xxxx
。這就是語言的工作原理。在Javascript中的所有屬性引用都需要一個對象作爲訪問的第一部分。並且,在構造函數中,新創建的對象的引用是this
。這就是語言的設計。
那些來自其他一些面向對象的語言的人可能會聲明一個類的實例變量,然後只是自己使用這個名稱,解釋器會知道它是一個實例變量名稱,而不是變量名稱。在其他一些語言中可能是這樣。在Javascript中這不是真的。所有屬性引用(無論是在構造函數中,某些方法中還是從外部作爲對象的屬性訪問)都必須使用一個對象作爲引用的基礎。並且,在構造函數和方法內部,該基數是this
的值。所以,this.someProperty
是你如何引用當前實例的屬性。
只要您離開它們定義的範圍,局部變量就會被銷燬。 – zerkms
您可以使用局部變量,但它們只能由構造函數中的代碼訪問。它們不是創建對象的屬性。如果你想分配對象的屬性,你必須引用對象本身'this.someProp = someValue'。有一些設計模式在構造函數中分配內聯方法,並且這些方法可以訪問構造函數中的局部變量,但這些變量不能直接從構造函數外部訪問。 – jfriend00
哦,屬性本質上是全球性的?這就是你爲什麼使用這個? –