常規的 {...}
語法允許建立一個物件。但是我們經常需要建立許多類似的物件,例如多個使用者或選單項等。
這可以使用建構函式和 "new"
操作符來實現。
建構函式在技術上是常規函數。不過有兩個約定:
"new"
操作符來執行。例如:
function User(name) { this.name = name; this.isAdmin = false; }let user = new User("Jack"); alert(user.name); // Jackalert(user.isAdmin); // false複製程式碼
當一個函數被使用 new
操作符執行時,它按照以下步驟:
this
。this
,為其新增新的屬性。this
的值。換句話說,new User(...)
做的就是類似的事情:
function User(name) { // this = {};(隱式建立) // 新增屬性到 this this.name = name; this.isAdmin = false; // return this;(隱式返回)}複製程式碼
所以 new User("Jack")
的結果是相同的物件:
let user = { name: "Jack", isAdmin: false};複製程式碼
現在,如果我們想建立其他使用者,我們可以呼叫 new User("Ann")
,new User("Alice")
等。比每次都使用字面量建立要短得多,而且更易於閱讀。
這是構造器的主要目的 —— 實現可重用的物件建立程式碼。
讓我們再強調一遍 —— 從技術上講,任何函數都可以用作構造器。即:任何函數都可以通過 new
來執行,它會執行上面的演演算法。「首字母大寫」是一個共同的約定,以明確表示一個函數將被使用 new
來執行。
如果我們有許多行用於建立單個複雜物件的程式碼,我們可以將它們封裝在建構函式中,像這樣:
let user = new function() { this.name = "John"; this.isAdmin = false; // ……用於使用者建立的其他程式碼 // 也許是複雜的邏輯和語句 // 區域性變數等};複製程式碼
構造器不能被再次呼叫,因為它不儲存在任何地方,只是被建立和呼叫。因此,這個技巧旨在封裝構建單個物件的程式碼,而無需將來重用。
進階內容:
本節涉及的語法內容很少使用,除非你想了解所有內容,否則你可以直接跳過該語法。
在一個函數內部,我們可以使用 new.target
屬性來檢查它是否被使用 new
進行呼叫了。
對於常規呼叫,它為空,對於使用 new
的呼叫,則等於該函數:
function User() { alert(new.target); }// 不帶 "new":User(); // undefined// 帶 "new":new User(); // function User { ... }複製程式碼
它可以被用在函數內部,來判斷該函數是被通過 new
呼叫的「構造器模式」,還是沒被通過 new
呼叫的「常規模式」。
我們也可以讓 new
呼叫和常規呼叫做相同的工作,像這樣:
function User(name) { if (!new.target) { // 如果你沒有通過 new 執行我 return new User(name); // ……我會給你新增 new } this.name = name; }let john = User("John"); // 將呼叫重定向到新使用者alert(john.name); // John複製程式碼
這種方法有時被用在庫中以使語法更加靈活。這樣人們在呼叫函數時,無論是否使用了 new
,程式都能工作。
不過,到處都使用它並不是一件好事,因為省略了 new
使得很難觀察到程式碼中正在發生什麼。而通過 new
我們都可以知道這建立了一個新物件。
通常,構造器沒有 return
語句。它們的任務是將所有必要的東西寫入 this
,並自動轉換為結果。
但是,如果這有一個 return
語句,那麼規則就簡單了:
return
返回的是一個物件,則返回這個物件,而不是 this
。return
返回的是一個原始型別,則忽略。換句話說,帶有物件的 return
返回該物件,在所有其他情況下返回 this
。
例如,這裡 return
通過返回一個物件覆蓋 this
:
function BigUser() { this.name = "John"; return { name: "Godzilla" }; // <-- 返回這個物件} alert( new BigUser().name ); // Godzilla,得到了那個物件複製程式碼
這裡有一個 return
為空的例子(或者我們可以在它之後放置一個原始型別,沒有什麼影響):
function SmallUser() { this.name = "John"; return; // <-- 返回 this} alert( new SmallUser().name ); // John複製程式碼
通常構造器沒有 return
語句。這裡我們主要為了完整性而提及返回物件的特殊行為。
順便說一下,如果沒有引數,我們可以省略 new
後的括號:
let user = new User; // <-- 沒有引數// 等同於let user = new User();複製程式碼
這裡省略括號不被認為是一種「好風格」,但是規範允許使用該語法。
使用建構函式來建立物件會帶來很大的靈活性。建構函式可能有一些引數,這些引數定義瞭如何構造物件以及要放入什麼。
當然,我們不僅可以將屬性新增到 this
中,還可以新增方法。
例如,下面的 new User(name)
用給定的 name
和方法 sayHi
建立了一個物件:
function User(name) { this.name = name; this.sayHi = function() { alert( "My name is: " + this.name ); }; }let john = new User("John"); john.sayHi(); // My name is: John/* john = { name: "John", sayHi: function() { ... } } */複製程式碼
類 是用於建立複雜物件的一個更高階的語法,我們稍後會講到。
new
來呼叫。這樣的呼叫意味著在開始時建立了空的 this
,並在最後返回填充了值的 this
。我們可以使用建構函式來建立多個類似的物件。
JavaScript 為許多內建的物件提供了建構函式:比如日期 Date
、集合 Set
以及其他我們計劃學習的內容。
物件,我們還會回來噠!
在本章中,我們只介紹了關於物件和構造器的基礎知識。它們對於我們在下一章中,學習更多關於資料型別和函數的相關知識非常重要。
在我們學習了那些之後,我們將回到物件,在 info:prototypes 和 info:classes 章節中深入介紹它們。
先自己做題目再看答案。
重要程度:⭐️⭐️
是否可以建立像 new A()==new B()
這樣的函數 A
和 B
?
function A() { ... }function B() { ... }let a = new A;let b = new B; alert( a == b ); // true複製程式碼
如果可以,請提供一個它們的程式碼範例。
重要程度:⭐️⭐️⭐️⭐️⭐️
建立一個建構函式 Calculator
,它建立的物件中有三個方法:
read()
使用 prompt
請求兩個值並把它們記錄在物件的屬性中。sum()
返回這些屬性的總和。mul()
返回這些屬性的乘積。例如:
let calculator = new Calculator(); calculator.read(); alert( "Sum=" + calculator.sum() ); alert( "Mul=" + calculator.mul() );複製程式碼
重要程度:⭐️⭐️⭐️⭐️⭐️
建立一個建構函式 Accumulator(startingValue)
。
它建立的物件應該:
value
中。起始值被設定到構造器 startingValue
的引數。read()
方法應該使用 prompt
來讀取一個新的數位,並將其新增到 value
中。換句話說,value
屬性是所有使用者輸入值與初始值 startingValue
的總和。
下面是範例程式碼:
let accumulator = new Accumulator(1); // 初始值 1accumulator.read(); // 新增使用者輸入的 valueaccumulator.read(); // 新增使用者輸入的 valuealert(accumulator.value); // 顯示這些值的總和複製程式碼
相關免費學習推薦:(視訊)
以上就是JavaScript 建構函式和 "new" 操作符詳解的詳細內容,更多請關注TW511.COM其它相關文章!