發布於 2023-08-03

更新於 2023-08-03

程式

約1040字 (6分鐘閱讀)

JavaScript: in vs. hasOwn vs. hasOwnProperty

Title Image

Photo by JavaScript on JavaScript

導言 - Lead paragraph

上一篇文章有說到 JavaScript 要如何檢驗物件是否包含屬性的方法,介紹到了 in 運算符 (in operator)hasOwn()hasOwnProperty()

在比對三者的差異性為何前,先來複習一下大略介紹的官方資訊:

hasOwn() 是 ECMAScript 2022(ES13)的新靜態方法,若指定的對象自身有指定的屬性,則 Object.hasOwn() 返回 true;若屬性是繼承的或者不存在,該方法返回 false

in 運算符、hasOwnProperty() 是在 ECMAScript 2022 (ES13) 以前出來的,較多人使用用來檢查 JS 對象是否具有任何自定義屬性的傳統方法。

  • in 運算符檢查屬性是否存在於物件及其原型鏈上。
  • hasOwnProperty() 檢查屬性是否存在於物件自身,不考慮原型鏈。

MSN

Compare the in operator, Object.hasOwn() and hasOwnProperty()

in 運算符甚至對於繼承的屬性也會返回 true,例如: toStringconstructorhasOwnProperty 是所有 JavaScript 對象的繼承方法。

以下示例區分直接屬性(Direct properties)和通過原型鏈繼承的屬性(Inherited properties):

let examples = {
    name: "Kama",
    website: "reikama414.github.io",
}

// `hasOwn` will only return true for direct properties:
Object.hasOwn(examples, 'name'); // true
Object.hasOwn(examples, 'toString'); // false
Object.hasOwn(examples, 'constructor'); // false
Object.hasOwn(examples, 'hasOwnProperty'); // false
  
// `in` operator will return true for direct or inherited properties:
'name' in examples; // true
'toString' in examples; // true
'constructor' in examples; // true
'hasOwnProperty' in examples; // true

// `hasOwnProperty` will only return true for direct properties:
examples.hasOwnProperty('name'); // true
examples.hasOwnProperty('toString'); // false
examples.hasOwnProperty('constructor'); // false
examples.hasOwnProperty('hasOwnProperty'); // false

Why Using Object.hasOwn() as a replacement for Object.hasOwnProperty()?

主要原因大致可分為兩種:

  • hasOwnProperty 可能會被覆蓋,但 hasOwn() 避免了這個問題,可以返回正確結果。
  • hasOwnProperty() 方法不適用於 null 對象,但 hasOwn() 方法適用。
hasOwnProperty 可能會被覆蓋

JavaScript 不保護屬性名 hasOwnProperty,具有此名稱屬性的對象可能會返回不正確的結果:

const person = {
  hasOwnProperty() {
    return false;
  },
  name: 'Kama',
};

// Use Object.hasOwn() method - recommended
Object.hasOwn(person, 'name'); // true

// Use the hasOwnProperty property from the Object prototype
Object.prototype.hasOwnProperty.call(person, 'name'); // true

// Use another Object's hasOwnProperty and call it with 'this' set to person
({}).hasOwnProperty.call(person, 'name'); // true

// re-implementation always returns false
person.hasOwnProperty('name'); // false

當還在使用 hasOwnProperty() 時,為了避免這種錯誤,最好始終從 Object.prototype 調用這些方法(e.g. 使用 Object.prototype.hasOwnProperty.call())。

不過有了 ES13 出來的 hasOwn() 以後,即便 hasOwnProperty() 被覆蓋,我們仍然可以確定屬性檢查將返回正確的結果。


It also may cause security issues. A specific example of this is when a web server reads in JSON data from a client and uses the hasOwnProperty property on that object. A problem could happen if client sends malicious JSON value like {"hasOwnProperty": 1} that would cause the server to fail.

一一 This excerpt is taken from "Reference" [5], written by Igor Gonchar.

(指 hasOwnProperty 可能會被覆蓋這件事) 這也可能導致安全問題。

一個具體示例是當 Web 服務器從客戶端讀取 JSON 資料並使用在該對象上使用 hasOwnProperty 屬性時。

如果客戶端發送諸如 {"hasOwnProperty": 1} 之類的惡意 JSON 值,則可能會出現問題,從而導致服務器失敗。

使用 Object.create(null) 創建的對象

使用 Object.create(null) 創建的對象不會繼承自 Object.prototype,從而導致 hasOwnProperty() 無法訪問。

hasOwnProperty() 方法不適用於 null 對象,但 hasOwn() 方法適用。

const example = Object.create(null);
example.type = "WEB";

Object.hasOwn(example, "type"); // true

// Uncaught TypeError: example.hasOwnProperty is not a function
example.hasOwnProperty("type");

Browser compatibility

結論 - Concluding

簡單來講,in 運算符 (in operator)hasOwn()hasOwnProperty() 可以分為:

  • 直接屬性(Direct properties)
    in 運算符*(in operator)*
  • 繼承屬性(Inherited properties)
    hasOwn()hasOwnProperty()

hasOwn()hasOwnProperty(),之所以建議使用 Object.hasOwn() 而不是 Object.hasOwnProperty() 的原因是:

因為 Object.hasOwn() 也適用於使用 Object.create(null) 創建的對象,以及覆蓋了繼承的 hasOwnProperty() 方法的對象。

儘管可以通過在外部對象上調用 Object.prototype.hasOwnProperty.call(<object reference>, <property name>) 解決這些問題,但 Object.hasOwn() 可以直接克服這些問題,因此更受推薦。

參考資料 - Reference

[1] JavaScript Object hasOwn() Method - GeeksforGeeks

https://www.geeksforgeeks.org/javascript-object-hasown-method/

[2] in operator - JavaScript | MDN

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in

[3] Object.hasOwn() - JavaScript | MDN

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn

[4] Object.prototype.hasOwnProperty() - JavaScript | MDN

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

[5] JavaScript: hasOwn() — new way to check if Object has property | by Igor Gonchar | Medium

https://igorgonchar.medium.com/javascript-hasown-new-way-to-check-if-object-has-property-b93810e47070

[6] javascript - Object.hasOwn() vs Object.prototype.hasOwnProperty() - Stack Overflow

https://stackoverflow.com/questions/69561596/object-hasown-vs-object-prototype-hasownproperty

JavaScript: in vs. hasOwn vs. hasOwnProperty

https:///blog/82

作者

Kama

Read more from 程式
lightbox-image
Toggle Button - Red Pandas Icons by svgrepo.com

Copyrights © 2023 Kama, All Rights Reserved.