W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
常規(guī)的 ?{...}
? 語法允許創(chuàng)建一個對象。但是我們經(jīng)常需要創(chuàng)建很多類似的對象,例如多個用戶或菜單項等。
這可以使用構(gòu)造函數(shù)和 ?"new"
? 操作符來實現(xiàn)。
構(gòu)造函數(shù)在技術上是常規(guī)函數(shù)。不過有兩個約定:
"new"
? 操作符來執(zhí)行。例如:
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("Jack");
alert(user.name); // Jack
alert(user.isAdmin); // false
當一個函數(shù)被使用 new
操作符執(zhí)行時,它按照以下步驟:
this
?。this
?,為其添加新的屬性。this
?的值。換句話說,new User(...)
做的就是類似的事情:
function User(name) {
// this = {};(隱式創(chuàng)建)
// 添加屬性到 this
this.name = name;
this.isAdmin = false;
// return this;(隱式返回)
}
所以 new User("Jack")
的結(jié)果是相同的對象:
let user = {
name: "Jack",
isAdmin: false
};
現(xiàn)在,如果我們想創(chuàng)建其他用戶,我們可以調(diào)用 new User("Ann")
,new User("Alice")
等。比每次都使用字面量創(chuàng)建要短得多,而且更易于閱讀。
這是構(gòu)造器的主要目的 —— 實現(xiàn)可重用的對象創(chuàng)建代碼。
讓我們再強調(diào)一遍 —— 從技術上講,任何函數(shù)(除了箭頭函數(shù),它沒有自己的 this
)都可以用作構(gòu)造器。即可以通過 new
來運行,它會執(zhí)行上面的算法?!笆鬃帜复髮憽笔且粋€共同的約定,以明確表示一個函數(shù)將被使用 new
來運行。
new function() { … }
如果我們有許多行用于創(chuàng)建單個復雜對象的代碼,我們可以將它們封裝在一個立即調(diào)用的構(gòu)造函數(shù)中,像這樣:
// 創(chuàng)建一個函數(shù)并立即使用 new 調(diào)用它 let user = new function() { this.name = "John"; this.isAdmin = false; // ……用于用戶創(chuàng)建的其他代碼 // 也許是復雜的邏輯和語句 // 局部變量等 };
這個構(gòu)造函數(shù)不能被再次調(diào)用,因為它不保存在任何地方,只是被創(chuàng)建和調(diào)用。因此,這個技巧旨在封裝構(gòu)建單個對象的代碼,而無需將來重用。
進階內(nèi)容
本節(jié)涉及的語法內(nèi)容很少使用,除非你想了解所有內(nèi)容,否則你可以直接跳過該語法。
在一個函數(shù)內(nèi)部,我們可以使用 new.target
屬性來檢查它是否被使用 new
進行調(diào)用了。
對于常規(guī)調(diào)用,它為 undefined,對于使用 new
的調(diào)用,則等于該函數(shù):
function User() {
alert(new.target);
}
// 不帶 "new":
User(); // undefined
// 帶 "new":
new User(); // function User { ... }
它可以被用在函數(shù)內(nèi)部,來判斷該函數(shù)是被通過 new
調(diào)用的“構(gòu)造器模式”,還是沒被通過 new
調(diào)用的“常規(guī)模式”。
我們也可以讓 new
調(diào)用和常規(guī)調(diào)用做相同的工作,像這樣:
function User(name) {
if (!new.target) { // 如果你沒有通過 new 運行我
return new User(name); // ……我會給你添加 new
}
this.name = name;
}
let john = User("John"); // 將調(diào)用重定向到新用戶
alert(john.name); // John
這種方法有時被用在庫中以使語法更加靈活。這樣人們在調(diào)用函數(shù)時,無論是否使用了 new
,程序都能工作。
不過,到處都使用它并不是一件好事,因為省略了 new
使得很難觀察到代碼中正在發(fā)生什么。而通過 new
我們都可以知道這創(chuàng)建了一個新對象。
通常,構(gòu)造器沒有 return
語句。它們的任務是將所有必要的東西寫入 this
,并自動轉(zhuǎn)換為結(jié)果。
但是,如果這有一個 return
語句,那么規(guī)則就簡單了:
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
通常構(gòu)造器沒有 return
語句。這里我們主要為了完整性而提及返回對象的特殊行為。
省略括號
順便說一下,如果沒有參數(shù),我們可以省略
new
后的括號:
let user = new User; // <-- 沒有參數(shù) // 等同于 let user = new User();
這里省略括號不被認為是一種“好風格”,但是規(guī)范允許使用該語法。
使用構(gòu)造函數(shù)來創(chuàng)建對象會帶來很大的靈活性。構(gòu)造函數(shù)可能有一些參數(shù),這些參數(shù)定義了如何構(gòu)造對象以及要放入什么。
當然,我們不僅可以將屬性添加到 this
中,還可以添加方法。
例如,下面的 new User(name)
用給定的 name
和方法 sayHi
創(chuàng)建了一個對象:
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() { ... }
}
*/
類 是用于創(chuàng)建復雜對象的一個更高級的語法,我們稍后會講到。
new
?來調(diào)用。這樣的調(diào)用意味著在開始時創(chuàng)建了空的 ?this
?,并在最后返回填充了值的 ?this
?。我們可以使用構(gòu)造函數(shù)來創(chuàng)建多個類似的對象。
JavaScript 為許多內(nèi)建的對象提供了構(gòu)造函數(shù):比如日期 Date
、集合 Set
以及其他我們計劃學習的內(nèi)容。
對象,我們還會回來噠!
在本章中,我們只介紹了關于對象和構(gòu)造器的基礎知識。它們對于我們在下一章中,學習更多關于數(shù)據(jù)類型和函數(shù)的相關知識非常重要。
重要程度: 2
是否可以創(chuàng)建像 new A() == new B()
這樣的函數(shù) A
和 B
?
function A() { ... }
function B() { ... }
let a = new A;
let b = new B;
alert( a == b ); // true
如果可以,請?zhí)峁┮粋€它們的代碼示例。
是的,這是可以的。
如果一個函數(shù)返回一個對象,那么 new
返回那個對象而不是 this
。
所以它們可以,例如,返回相同的外部定義的對象 obj
:
let obj = {};
function A() { return obj; }
function B() { return obj; }
alert( new A() == new B() ); // true
重要程度: 5
創(chuàng)建一個構(gòu)造函數(shù) Calculator
,它創(chuàng)建的對象中有三個方法:
read()
? 使用 ?prompt
?請求兩個值并把它們記錄在對象的屬性中。sum()
? 返回這些屬性的總和。mul()
? 返回這些屬性的乘積。例如:
let calculator = new Calculator();
calculator.read();
alert( "Sum=" + calculator.sum() );
alert( "Mul=" + calculator.mul() );
function Calculator() {
this.read = function() {
this.a = +prompt('a?', 0);
this.b = +prompt('b?', 0);
};
this.sum = function() {
return this.a + this.b;
};
this.mul = function() {
return this.a * this.b;
};
}
let calculator = new Calculator();
calculator.read();
alert( "Sum=" + calculator.sum() );
alert( "Mul=" + calculator.mul() );
重要程度: 5
創(chuàng)建一個構(gòu)造函數(shù) Accumulator(startingValue)
。
它創(chuàng)建的對象應該:
value
?中。起始值被設置到構(gòu)造器 ?startingValue
?的參數(shù)。read()
? 方法應該使用 ?prompt
?來讀取一個新的數(shù)字,并將其添加到 ?value
?中。換句話說,?value
?屬性是所有用戶輸入值與初始值 ?startingValue
?的總和。
下面是示例代碼:
let accumulator = new Accumulator(1); // 初始值 1
accumulator.read(); // 添加用戶輸入的 value
accumulator.read(); // 添加用戶輸入的 value
alert(accumulator.value); // 顯示這些值的總和
function Accumulator(startingValue) {
this.value = startingValue;
this.read = function() {
this.value += +prompt('How much to add?', 0);
};
}
let accumulator = new Accumulator(1);
accumulator.read();
accumulator.read();
alert(accumulator.value);
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: