當涉及JavaScript語言與其他程式語言相比時,你可能會聽到一些令人困惑東西,其中之一是工廠函數和建構函數。
所謂工廠函數,就是指這些內建函數都是類別對象,當你呼叫他們時,實際上是創建了一個類別實例」。意思是當我調用這個函數,實際上是先利用類別創建了一個對象,然後返回這個對象。由於Javascript 本身不是嚴格的面向對象的語言(不包含類別),實際上來說,Javascript 並沒有嚴格的“工廠函數”,但是在Javascript中,我們能利用函數模擬類別。來看下面一個例子:
function person(firstName, lastName, age) { const person = {}; person.firstName = firstName; person.lastName = lastName; person.age = age; return person; }
上述程式碼,創建一個新對象,並將傳遞參數作為屬性附加到該物件上並傳回新物件。這是一個簡單的JavaScript 工廠函數。
#實際上工廠函數也很好理解了:
#它是一個函數。
它用來創建物件。
它像工廠一樣,「生產」出來的函數都是「標準件」(擁有相同的屬性)
不同於其它的主流程式語言,JavaScript的建構函數並不是作為類別的一個特定方法存在的;當任意一個普通函數用來建立一類物件時,它就被稱為建構函數,或建構子。一個函數要作為一個真正意義上的建構函數,需要滿足下列條件:
在函數內部對新物件(this)的屬性進行設置,通常是新增屬性和方法。
function Person(firstName, lastName, age) { this.firstName = firstName; this.lastName = lastName; this.age = age; }
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。好的,讓我們用建構函數來做同樣的實驗。
// 要点一:自由扩展属性 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__); // 要点三:函数有 prototype console.log(fn.prototype) // 要点四:引用类型的 __proto__ 属性值指向它的构造函数的 prototype 属性值 console.log(obj.__proto__ === Object.prototype)
,因為它們用於建立物件。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 关键字,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关键字,对输出都没有影响。
JavaScript 中有许多概念,有时难以掌握。 new
操作符就是其中之一。 如果你不能正确理解它,那么在运行 JavaScript 应用程序时会产生令人讨厌的后果。 在像 Java这 样的语言中,严格限制了如何使用 new
关键字。 但是在 javascript 中,并不是那么严格,如果你不能正确理解它们可能会导致很多问题。
在 JavaScript 中:
new
运算符new
关键字将函数作为构造函数调用让我们看看上面的例子,使用和不使用 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中的工作原理非常关键的原因。
原文地址:https://medium.com/@chamikakasun/javascript-factory-functions-vs-constructor-functions-585919818afe
更多编程相关知识,请访问:编程入门!!
以上是淺談JavaScript中工廠函數與建構函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!