Object

Baseline Widely available *

This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.

* Some parts of this feature may have varying levels of support.

Kiểu Object đại diện cho một trong các kiểu dữ liệu của JavaScript. Nó được dùng để lưu trữ các tập hợp dữ liệu theo khóa và các thực thể phức tạp hơn. Object có thể được tạo bằng constructor Object() hoặc cú pháp object initializer / literal.

Description

Hầu hết tất cả object trong JavaScript đều là instance của Object; một object thông thường kế thừa các thuộc tính (bao gồm cả phương thức) từ Object.prototype, mặc dù các thuộc tính này có thể bị che khuất (hay còn gọi là ghi đè). Các object duy nhất không kế thừa từ Object.prototype là những object có prototype null, hoặc được kế thừa từ các object có prototype null khác.

Các thay đổi đối với đối tượng Object.prototype sẽ được tất cả các object nhìn thấy thông qua chuỗi prototype, trừ khi các thuộc tính và phương thức chịu ảnh hưởng bởi những thay đổi đó bị ghi đè ở phần sau của chuỗi prototype. Điều này tạo ra một cơ chế rất mạnh mẽ, dù có thể gây nguy hiểm, để ghi đè hoặc mở rộng hành vi của object. Để an toàn hơn, Object.prototype là đối tượng duy nhất trong ngôn ngữ JavaScript cốt lõi có prototype bất biến (immutable prototype) — prototype của Object.prototype luôn là null và không thể thay đổi.

Các thuộc tính prototype của Object

Bạn nên tránh gọi trực tiếp bất kỳ phương thức Object.prototype nào từ instance, đặc biệt là những phương thức không có tính đa hình (tức là chỉ có hành vi ban đầu có ý nghĩa và không có đối tượng kế thừa nào có thể ghi đè theo cách có ý nghĩa). Tất cả các object kế thừa từ Object.prototype đều có thể định nghĩa một thuộc tính riêng cùng tên, nhưng với ngữ nghĩa hoàn toàn khác với những gì bạn mong đợi. Hơn nữa, các thuộc tính này không được kế thừa bởi các object có prototype null. Tất cả các tiện ích JavaScript hiện đại để làm việc với object đều là static. Cụ thể hơn:

Trong trường hợp không tồn tại static method tương đương về ngữ nghĩa, hoặc nếu bạn thực sự muốn dùng phương thức Object.prototype, bạn nên trực tiếp call() phương thức Object.prototype đó trên đối tượng đích, để tránh trường hợp object có thuộc tính ghi đè gây ra kết quả không mong đợi.

js
const obj = {
  foo: 1,
  // You should not define such a method on your own object,
  // but you may not be able to prevent it from happening if
  // you are receiving the object from external input
  propertyIsEnumerable() {
    return false;
  },
};

obj.propertyIsEnumerable("foo"); // false; unexpected result
Object.prototype.propertyIsEnumerable.call(obj, "foo"); // true; expected result

Xóa thuộc tính khỏi object

Không có phương thức nào trong Object để xóa thuộc tính của chính nó (như Map.prototype.delete()). Muốn làm vậy, phải dùng toán tử delete.

Object có prototype null

Hầu hết tất cả object trong JavaScript cuối cùng đều kế thừa từ Object.prototype (xem kế thừa và chuỗi prototype). Tuy nhiên, bạn có thể tạo object có prototype null bằng cách dùng Object.create(null) hoặc cú pháp object initializer với __proto__: null (lưu ý: khóa __proto__ trong object literal khác với thuộc tính Object.prototype.__proto__ đã bị deprecated). Bạn cũng có thể thay đổi prototype của object hiện có thành null bằng cách gọi Object.setPrototypeOf(obj, null).

js
const obj = Object.create(null);
const obj2 = { __proto__: null };

Một object có prototype null có thể hoạt động theo những cách không mong đợi, vì nó không kế thừa bất kỳ phương thức object nào từ Object.prototype. Điều này đặc biệt đúng khi debug, vì các hàm tiện ích chuyển đổi/phát hiện thuộc tính phổ biến có thể gây lỗi, hoặc mất thông tin (đặc biệt khi dùng các bẫy lỗi im lặng mà bỏ qua lỗi).

Ví dụ, việc thiếu Object.prototype.toString() thường làm cho việc debug trở nên khó khăn:

js
const normalObj = {}; // create a normal object
const nullProtoObj = Object.create(null); // create an object with "null" prototype

console.log(`normalObj is: ${normalObj}`); // shows "normalObj is: [object Object]"
console.log(`nullProtoObj is: ${nullProtoObj}`); // throws error: Cannot convert object to primitive value

alert(normalObj); // shows [object Object]
alert(nullProtoObj); // throws error: Cannot convert object to primitive value

Các phương thức khác cũng sẽ thất bại.

js
normalObj.valueOf(); // shows {}
nullProtoObj.valueOf(); // throws error: nullProtoObj.valueOf is not a function

normalObj.hasOwnProperty("p"); // shows "true"
nullProtoObj.hasOwnProperty("p"); // throws error: nullProtoObj.hasOwnProperty is not a function

normalObj.constructor; // shows "Object() { [native code] }"
nullProtoObj.constructor; // shows "undefined"

Chúng ta có thể thêm lại phương thức toString cho object có prototype null bằng cách gán:

js
nullProtoObj.toString = Object.prototype.toString; // since new object lacks toString, add the original generic one back

console.log(nullProtoObj.toString()); // shows "[object Object]"
console.log(`nullProtoObj is: ${nullProtoObj}`); // shows "nullProtoObj is: [object Object]"

Khác với các object thông thường, nơi toString() nằm trên prototype của object, phương thức toString() ở đây là thuộc tính riêng của nullProtoObj. Đó là vì nullProtoObj không có prototype (null).

Bạn cũng có thể khôi phục object có prototype null trở lại thành object thông thường bằng cách dùng Object.setPrototypeOf(nullProtoObj, Object.prototype).

Trong thực tế, object có prototype null thường được dùng như một thay thế rẻ tiền cho map. Sự hiện diện của các thuộc tính Object.prototype sẽ gây ra một số lỗi:

js
const ages = { alice: 18, bob: 27 };

function hasPerson(name) {
  return name in ages;
}

function getAge(name) {
  return ages[name];
}

hasPerson("hasOwnProperty"); // true
getAge("toString"); // [Function: toString]

Dùng object có prototype null loại bỏ nguy cơ này mà không làm phức tạp thêm các hàm hasPersongetAge:

js
const ages = Object.create(null, {
  alice: { value: 18, enumerable: true },
  bob: { value: 27, enumerable: true },
});

hasPerson("hasOwnProperty"); // false
getAge("toString"); // undefined

Trong trường hợp như vậy, việc thêm bất kỳ phương thức nào cũng cần được thực hiện thận trọng, vì chúng có thể bị nhầm lẫn với các cặp khóa-giá trị được lưu trữ dưới dạng dữ liệu.

Việc object của bạn không kế thừa từ Object.prototype cũng ngăn chặn tấn công prototype pollution. Nếu một đoạn script độc hại thêm thuộc tính vào Object.prototype, nó sẽ có thể truy cập được trên mọi object trong chương trình của bạn, ngoại trừ các object có prototype null.

js
const user = {};

// A malicious script:
Object.prototype.authenticated = true;

// Unexpectedly allowing unauthenticated user to pass through
if (user.authenticated) {
  // access confidential data
}

JavaScript cũng có các API tích hợp tạo ra các object có prototype null, đặc biệt là những API dùng object như các tập hợp khóa-giá trị tùy ý. Ví dụ:

Thuật ngữ "object có prototype null" thường cũng bao gồm bất kỳ object nào không có Object.prototype trong chuỗi prototype của nó. Các object như vậy có thể được tạo bằng extends null khi dùng class.

Ép buộc sang Object (Object coercion)

Nhiều thao tác tích hợp sẵn mong đợi object sẽ ép buộc đối số của chúng thành object trước. Thao tác này có thể được tóm tắt như sau:

Có hai cách để đạt được hiệu quả gần như tương tự trong JavaScript.

  • Object.prototype.valueOf(): Object.prototype.valueOf.call(x) thực hiện chính xác các bước ép buộc object đã giải thích ở trên để chuyển đổi x.
  • Hàm Object(): Object(x) dùng cùng thuật toán để chuyển đổi x, ngoại trừ undefinednull không ném TypeError, mà trả về một object thuần.

Các nơi sử dụng object coercion bao gồm:

  • Tham số object của vòng lặp for...in.
  • Giá trị this của các phương thức Array.
  • Các tham số của phương thức Object như Object.keys().
  • Auto-boxing khi một thuộc tính được truy cập trên một giá trị primitive, vì primitive không có thuộc tính.
  • Giá trị this khi gọi một hàm non-strict. Primitive được boxing còn nullundefined được thay thế bằng global object.

Khác với chuyển đổi sang primitive, bản thân quá trình object coercion không thể quan sát được theo bất kỳ cách nào, vì nó không gọi code tùy chỉnh như các phương thức toString hay valueOf.

Constructor

Object()

Chuyển đổi đầu vào thành một object.

Static methods

Object.assign()

Sao chép các giá trị của tất cả thuộc tính riêng có thể liệt kê từ một hoặc nhiều object nguồn sang một object đích.

Object.create()

Tạo một object mới với đối tượng prototype và thuộc tính đã chỉ định.

Object.defineProperties()

Thêm các thuộc tính được đặt tên được mô tả bởi các descriptor cho trước vào một object.

Object.defineProperty()

Thêm thuộc tính được đặt tên được mô tả bởi một descriptor cho trước vào một object.

Object.entries()

Trả về một mảng chứa tất cả các cặp [key, value] của các thuộc tính string riêng có thể liệt kê của một object.

Object.freeze()

Đóng băng một object. Code khác không thể xóa hoặc thay đổi thuộc tính của nó.

Object.fromEntries()

Trả về một object mới từ một iterable gồm các cặp [key, value]. (Đây là phép đảo của Object.entries).

Object.getOwnPropertyDescriptor()

Trả về một property descriptor cho thuộc tính được đặt tên trên một object.

Object.getOwnPropertyDescriptors()

Trả về một object chứa tất cả property descriptor riêng của một object.

Object.getOwnPropertyNames()

Trả về một mảng chứa tên của tất cả thuộc tính riêng có thể liệt kê và không thể liệt kê của object đã cho.

Object.getOwnPropertySymbols()

Trả về một mảng gồm tất cả thuộc tính symbol được tìm thấy trực tiếp trên object đã cho.

Object.getPrototypeOf()

Trả về prototype (thuộc tính [[Prototype]] nội bộ) của object đã chỉ định.

Object.groupBy()

Nhóm các phần tử của một iterable theo các giá trị chuỗi được trả về bởi một callback function cho trước. Object trả về có các thuộc tính riêng biệt cho mỗi nhóm, chứa các mảng với các phần tử trong nhóm đó.

Object.hasOwn()

Trả về true nếu object đã chỉ định có thuộc tính đã cho là thuộc tính riêng của nó, hoặc false nếu thuộc tính được kế thừa hoặc không tồn tại.

Object.is()

So sánh xem hai giá trị có giống nhau không. Coi tất cả giá trị NaN là bằng nhau (khác với IsLooselyEqual dùng bởi ==IsStrictlyEqual dùng bởi ===).

Object.isExtensible()

Xác định xem object có được phép mở rộng hay không.

Object.isFrozen()

Xác định xem object có bị đóng băng hay không.

Object.isSealed()

Xác định xem object có bị niêm phong hay không.

Object.keys()

Trả về một mảng chứa tên của tất cả thuộc tính string riêng có thể liệt kê của object đã cho.

Object.preventExtensions()

Ngăn chặn mọi việc mở rộng đối với một object.

Object.seal()

Ngăn code khác xóa các thuộc tính của một object.

Object.setPrototypeOf()

Đặt prototype của object (thuộc tính [[Prototype]] nội bộ của nó).

Object.values()

Trả về một mảng chứa các giá trị tương ứng với tất cả thuộc tính string riêng có thể liệt kê của object đã cho.

Instance properties

Các thuộc tính này được định nghĩa trên Object.prototype và chia sẻ cho tất cả các instance của Object.

Object.prototype.__proto__ Deprecated

Trỏ đến object được dùng làm prototype khi object được khởi tạo.

Object.prototype.constructor

Hàm constructor đã tạo ra đối tượng instance. Với các instance Object thuần, giá trị ban đầu là constructor Object. Các instance của constructor khác đều kế thừa thuộc tính constructor từ đối tượng Constructor.prototype tương ứng của chúng.

Instance methods

Object.prototype.__defineGetter__() Deprecated

Liên kết một hàm với một thuộc tính, khi được truy cập, hàm đó sẽ được thực thi và trả về giá trị của nó.

Object.prototype.__defineSetter__() Deprecated

Liên kết một hàm với một thuộc tính, khi được gán, hàm đó sẽ được thực thi để thay đổi thuộc tính.

Object.prototype.__lookupGetter__() Deprecated

Trả về hàm được liên kết dưới dạng getter với thuộc tính đã chỉ định.

Object.prototype.__lookupSetter__() Deprecated

Trả về hàm được liên kết dưới dạng setter với thuộc tính đã chỉ định.

Object.prototype.hasOwnProperty()

Trả về giá trị boolean cho biết object có chứa thuộc tính đã chỉ định như một thuộc tính trực tiếp của object đó và không được kế thừa qua chuỗi prototype hay không.

Object.prototype.isPrototypeOf()

Trả về giá trị boolean cho biết object mà phương thức này được gọi có nằm trong chuỗi prototype của object đã chỉ định hay không.

Object.prototype.propertyIsEnumerable()

Trả về giá trị boolean cho biết thuộc tính đã chỉ định có phải là thuộc tính riêng có thể liệt kê của object hay không.

Object.prototype.toLocaleString()

Gọi toString().

Object.prototype.toString()

Trả về biểu diễn chuỗi của object.

Object.prototype.valueOf()

Trả về giá trị primitive của object đã chỉ định.

Examples

Tạo object rỗng

Ví dụ sau tạo các object rỗng bằng từ khóa new với các đối số khác nhau:

js
const o1 = new Object();
const o2 = new Object(undefined);
const o3 = new Object(null);

Dùng constructor Object() để chuyển đổi primitive thành Object

Bạn có thể dùng constructor Object() để tạo một object bọc (wrapper) cho một giá trị primitive.

Ví dụ sau tạo các biến o1o2 là các object lưu trữ giá trị BooleanBigInt:

js
// Equivalent to const o1 = new Boolean(true)
const o1 = new Object(true);

// No equivalent because BigInt() can't be called as a constructor,
// and calling it as a regular function won't create an object
const o2 = new Object(1n);

Prototype của Object

Khi thay đổi hành vi của các phương thức Object.prototype hiện có, hãy cân nhắc chèn code bằng cách bọc phần mở rộng của bạn trước hoặc sau logic hiện có. Ví dụ, code (chưa kiểm tra) này sẽ thực thi logic tùy chỉnh theo điều kiện trước khi logic tích hợp hoặc mở rộng của người khác được thực thi.

Khi sửa đổi prototype bằng hook, hãy truyền this và các đối số (trạng thái gọi) cho hành vi hiện tại bằng cách gọi apply() trên hàm. Pattern này có thể dùng cho bất kỳ prototype nào, chẳng hạn như Node.prototype, Function.prototype, v.v.

js
const current = Object.prototype.valueOf;

// Since my property "-prop-value" is cross-cutting and isn't always
// on the same prototype chain, I want to modify Object.prototype:
Object.prototype.valueOf = function (...args) {
  if (Object.hasOwn(this, "-prop-value")) {
    return this["-prop-value"];
  }
  // It doesn't look like one of my objects, so let's fall back on
  // the default behavior by reproducing the current behavior as best we can.
  // The apply behaves like "super" in some other languages.
  // Even though valueOf() doesn't take arguments, some other hook may.
  return current.apply(this, args);
};

Warning: Việc sửa đổi thuộc tính prototype của bất kỳ constructor tích hợp nào được coi là thực hành xấu và gây rủi ro về tính tương thích trong tương lai.

Bạn có thể đọc thêm về prototype trong Kế thừa và chuỗi prototype.

Specifications

Specification
ECMAScript® 2027 Language Specification
# sec-object-objects

Browser compatibility

See also