首頁  >  文章  >  web前端  >  淺談JavaScript中工廠函數與建構函數

淺談JavaScript中工廠函數與建構函數

青灯夜游
青灯夜游轉載
2020-11-30 18:05:494093瀏覽

淺談JavaScript中工廠函數與建構函數

當涉及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)的屬性進行設置,通常是新增屬性和方法。

  • ##建構函數可以包含傳回語句(不建議),但傳回值必須是this,或者其它非物件類型的值。

function Person(firstName, lastName, age) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.age = age;
}

使用new 關鍵字建立物件

正如上面所說的,我們可以使用

new 來類別或對象,那麼你可能會有以下幾個問題:

    我們可以在工廠函數中使用
  1. new 關鍵字嗎?
  2. 如果我們在工廠和建構函式中使用
  3. new關鍵字會發生什麼
  4. 如果在在使用建構函式建立物件實例時不使用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);

淺談JavaScript中工廠函數與建構函數

正如我們在上述所看到的,這裡的

__proto__ 指向其原型物件的指針,讓我們試著找出原型對像是什麼。為了找出上面mike物件的指向原型對象,讓我們做簡單的===等式檢查。

淺談JavaScript中工廠函數與建構函數

嗯,有趣的是,它指向

Object.prototype。好的,讓我們用建構函數來做同樣的實驗。

在理解JavaScript 的原型

在理解原型之前,需要記住以下幾點知識:

    所有的引用型別(陣列、物件、函數),都具有物件特性,即可自由擴充屬性(null除外)
  • 所有的參考類型(陣列、物件、函數),都有一個__proto__屬性,屬性值就是一個普通的物件
  • 所有的函數,都有一個prototype屬性,屬性值也是一個普通的物件
  • 所有的參考類型(陣列、物件、函數),__proto__屬性值指向它的建構函數的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)

使用建構子##注意:在JavaScript中,這些構造函數也被稱為

constructor
,因為它們用於建立物件。
function Person(firstName, lastName, age) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.age = age;
}
const mike = new Person('mike', 'grand', 23);

淺談JavaScript中工廠函數與建構函數當我們展開第一層的的

__proto__

時,它內部還有另一個__proto__,我們再次擴展它。

淺談JavaScript中工廠函數與建構函數現在讓我們試著弄清楚原型物件是否像上面一樣。

他们是不同的。 当我们使用工厂函数创建对象时,它的__proto__指向Object.prototype,而当从构造函数创建对象时,它指向它的构造函数原型对象。 那么这里发生了什么?

new 背后所做的事

当我们在创建对象时使用带有构造函数的new关键字时,new 背后所做的事不多。

new 运算符创建一个用户自定义的对象类型的实例或具有构造函数的内置对象的实例。 new 关键字会进行如下操作:

  1. 创建一个空的简单 JavaScript 对象 (即 {})
  2. 链接该对象(即设置该对象的构造函数)到另一个对象
  3. 将步骤1新创建的对象作为 this 的上下文
  4. 如果该函数没有返回对象,则返回 this

注释行是伪代码,表示在 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 运算符
  • 可以使用或不使用 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);

然后,如果查看创建的对象实例,你希望看到什么?

淺談JavaScript中工廠函數與建構函數

发生了什么? 使用 new 运算符,正如我们所期待的一样输出正确的对象,但没有new运算符,结果是undefined 怎么可能呢?

如果你对 JavaScript 作用域 this 关键字的工作原理有所了解,那么你可以猜到这里发生了什么? 让我们来看看。

淺談JavaScript中工廠函數與建構函數

看起来我们传递给没有new关键字的函数的所有属性都已设置为window对象。 那是因为到那个时候函数内部的这个变量引用了globalwindow 对象,基本上我们在这里做的就是污染了全局对象。

这是你可以对你的JavaScript程序做的非常讨厌的事情。 因此,使用new运算符,JavaScript引擎将this 变量设置为引用新创建的对象实例,这就是为什么我们可以看到传递给构造函数的所有属性都已设置为 mike

但是在没有new运算符的情况下调用构造函数的情况下,JavaScript 引擎会将 this 解释为常规函数调用,而没有显式返回语句时返回undefined。 这就是理解new 运算符在JavaScript中的工作原理非常关键的原因。

原文地址:https://medium.com/@chamikakasun/javascript-factory-functions-vs-constructor-functions-585919818afe

更多编程相关知识,请访问:编程入门!!

以上是淺談JavaScript中工廠函數與建構函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除