前言
當談到JavaScript語言與其他編程語言相比時,你可能會聽到一些令人困惑東西,其中之一是工廠函數和構造函數。
工廠函數
所謂工廠函數,就是指這些內建函數都是類對象,當你調用他們時,實際上是創建了一個類實例”。意思就是當我調用這個函數,實際上是先利用類創建了一個對象,然后返回這個對象。由于 Javascript 本身不是嚴格的面向對象的語言(不包含類),實際上來說,Javascript 并沒有嚴格的“工廠函數”,但是在 Javascript中,我們能利用函數模擬類。來看下面一個例子:
function person(firstName, lastName, age) { const person = {}; person.firstName = firstName; person.lastName = lastName; person.age = age; return person;}
上述代碼,創建一個新對象,并將傳遞參數作為屬性附加到該對象上并返回新對象。 這是一個簡單的 JavaScript 工廠函數。
實際上工廠函數也很好理解了:
構造函數
不同于其它的主流編程語言,JavaScript的構造函數并不是作為類的一個特定方法存在的;當任意一個普通函數用于創建一類對象時,它就被稱作構造函數,或構造器。一個函數要作為一個真正意義上的構造函數,需要滿足下列條件:
function Person(firstName, lastName, age) { this.firstName = firstName; this.lastName = lastName; this.age = age;}
使用 new 關鍵字創建對象
正如上面所說的,我們可以使用 new 來類或者對象,那么你可能會有以下幾個問題:
好的,試著找出以上問題的答案之前,我們先做一個小練習來理解這里面發生了什么。
使用new關鍵字同時使用工廠和構造函數創建兩個對象,接著在控制臺打印這兩個對象。
使用工廠函數
function person(firstName, lastName, age){ const person = {} person.firstName = firstName; person.lastName = lastName; person.age = age; return person;}const mike = new person('mike', 'grand', 23);
正如我們在上述所看到的,這里的__proto__ 指向其原型對象的指針,讓我們試著找出原型對象是什么。為了找出上面mike對象的指向原型對象,讓我們做簡單的===等式檢查。
嗯,有趣的是,它指向 Object.prototype。好的,讓我們用構造函數做同樣的實驗。
理解 JavaScript 的原型
理解原型之前,需要記住以下幾點知識:
通過代碼解釋一下:
// 要點一:自由擴展屬性var obj = {}; obj.a = 100;var arr = []; arr.a = 100;function fn () {}fn.a = 100;// 要點二:__proto__console.log(obj.__proto__);console.log(arr.__proto__);console.log(fn.__proto__);// 要點三:函數有 prototypeconsole.log(fn.prototype)// 要點四:引用類型的 __proto__ 屬性值指向它的構造函數的 prototype 屬性值console.log(obj.__proto__ === Object.prototype)
使用構造函數
注意:在JavaScript中,這些構造函數也被稱為 constructor,因為它們用于創建對象。
function Person(firstName, lastName, age) { this.firstName = firstName; this.lastName = lastName; this.age = age;}const mike = new Person('mike', 'grand', 23);
當我們展開第一層的的__proto__時,它內部還有另一個__proto__,我們再次擴展它。
現在讓我們試著弄清楚原型對象是否像上面一樣。
他們是不同的。 當我們使用工廠函數創建對象時,它的__proto__指向Object.prototype,而當從構造函數創建對象時,它指向它的構造函數原型對象。 那么這里發生了什么?
new 背后所做的事
當我們在創建對象時使用帶有構造函數的new關鍵字時,new 背后所做的事不多。
new 運算符創建一個用戶自定義的對象類型的實例或具有構造函數的內置對象的實例。 new 關鍵字會進行如下操作:
注釋行是偽代碼,表示在 new 關鍵字,JS 背后幫我們做的事情。
function Person(firstName, lastName, age) { // this = {}; // this.__proto__ = Person.prototype; this.firstName = firstName; this.lastName = lastName; this.age = age; // return this;}
另外,讓我們看看如果將上面的隱式代碼添加到工廠函數中會發生什么。
function person(firstName, lastName, age) { // this = {}; // this.__proto__ = Person.prototype; const person = {}; person.firstName = firstName; person.lastName = lastName; person.age = age; return person; // return this;}
即使使用new關鍵字調用時將隱式代碼添加到工廠函數中,也不會對結果產生任何影響。這是因為,由于我們沒有在函數中使用 this 關鍵字,而且我們顯式地返回了一個除this之外的自定義對象,因此沒有必要使用隱式代碼。無論我們是否對工廠函數使用new關鍵字,對輸出都沒有影響。
如果忘記了 new 關鍵字怎么辦
JavaScript 中有許多概念,有時難以掌握。 new 操作符就是其中之一。 如果你不能正確理解它,那么在運行 JavaScript 應用程序時會產生令人討厭的后果。 在像 Java這 樣的語言中,嚴格限制了如何使用 new 關鍵字。 但是在 javascript 中,并不是那么嚴格,如果你不能正確理解它們可能會導致很多問題。
在 JavaScript 中:
讓我們看看上面的例子,使用和不使用 new 關鍵情況
function Person(firstName, lastName, age) {this.firstName = firstName;this.lastName = lastName;this.age = age;}const mike = new Person('mike', 'grand', 23);const bob = Person('bob', 'grand', 23);
然后,如果查看創建的對象實例,你希望看到什么?
發生了什么? 使用 new 運算符,正如我們所期待的一樣輸出正確的對象,但沒有new運算符,結果是undefined 怎么可能呢?
如果你對 JavaScript 作用域 和 this 關鍵字的工作原理有所了解,那么你可以猜到這里發生了什么? 讓我們來看看。
看起來我們傳遞給沒有new關鍵字的函數的所有屬性都已設置為window對象。 那是因為到那個時候函數內部的這個變量引用了global 或 window 對象,基本上我們在這里做的就是污染了全局對象。
這是你可以對你的JavaScript程序做的非常討厭的事情。 因此,使用new運算符,JavaScript引擎將this 變量設置為引用新創建的對象實例,這就是為什么我們可以看到傳遞給構造函數的所有屬性都已設置為 mike。
但是在沒有new運算符的情況下調用構造函數的情況下,JavaScript 引擎會將 this 解釋為常規函數調用,而沒有顯式返回語句時返回undefined。 這就是理解new 運算符在JavaScript中的工作原理非常關鍵的原因。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對VeVb武林網的支持。
新聞熱點
疑難解答