Object

A few additional static helpers have been added to Object. Traditionally, functions of this sort have been seen as focused on the behaviors/capabilities of object values.

However, starting with ES6, Object static functions will also be for general-purpose global APIs of any sort that don’t already belong more naturally in some other location (i.e., Array.from(..)).

Object.is(..) Static Function

The Object.is(..) static function makes value comparisons in an even more strict fashion than the === comparison.

Object.is(..) invokes the underlying SameValue algorithm (ES6 spec, section 7.2.9). The SameValue algorithm is basically the same as the === Strict Equality Comparison Algorithm (ES6 spec, section 7.2.13), with two important exceptions.

Consider:

  1. var x = NaN, y = 0, z = -0;
  2. x === x; // false
  3. y === z; // true
  4. Object.is( x, x ); // true
  5. Object.is( y, z ); // false

You should continue to use === for strict equality comparisons; Object.is(..) shouldn’t be thought of as a replacement for the operator. However, in cases where you’re trying to strictly identify a NaN or -0 value, Object.is(..) is now the preferred option.

Note: ES6 also adds a Number.isNaN(..) utility (discussed later in this chapter) which may be a slightly more convenient test; you may prefer Number.isNaN(x) over Object.is(x,NaN). You can accurately test for -0 with a clumsy x == 0 && 1 / x === -Infinity, but in this case Object.is(x,-0) is much better.

Object.getOwnPropertySymbols(..) Static Function

The “Symbols” section in Chapter 2 discusses the new Symbol primitive value type in ES6.

Symbols are likely going to be mostly used as special (meta) properties on objects. So the Object.getOwnPropertySymbols(..) utility was introduced, which retrieves only the symbol properties directly on an object:

  1. var o = {
  2. foo: 42,
  3. [ Symbol( "bar" ) ]: "hello world",
  4. baz: true
  5. };
  6. Object.getOwnPropertySymbols( o ); // [ Symbol(bar) ]

Object.setPrototypeOf(..) Static Function

Also in Chapter 2, we mentioned the Object.setPrototypeOf(..) utility, which (unsurprisingly) sets the [[Prototype]] of an object for the purposes of behavior delegation (see the this & Object Prototypes title of this series). Consider:

  1. var o1 = {
  2. foo() { console.log( "foo" ); }
  3. };
  4. var o2 = {
  5. // .. o2's definition ..
  6. };
  7. Object.setPrototypeOf( o2, o1 );
  8. // delegates to `o1.foo()`
  9. o2.foo(); // foo

Alternatively:

  1. var o1 = {
  2. foo() { console.log( "foo" ); }
  3. };
  4. var o2 = Object.setPrototypeOf( {
  5. // .. o2's definition ..
  6. }, o1 );
  7. // delegates to `o1.foo()`
  8. o2.foo(); // foo

In both previous snippets, the relationship between o2 and o1 appears at the end of the o2 definition. More commonly, the relationship between an o2 and o1 is specified at the top of the o2 definition, as it is with classes, and also with __proto__ in object literals (see “Setting [[Prototype]]“ in Chapter 2).

Warning: Setting a [[Prototype]] right after object creation is reasonable, as shown. But changing it much later is generally not a good idea and will usually lead to more confusion than clarity.

Object.assign(..) Static Function

Many JavaScript libraries/frameworks provide utilities for copying/mixing one object’s properties into another (e.g., jQuery’s extend(..)). There are various nuanced differences between these different utilities, such as whether a property with value undefined is ignored or not.

ES6 adds Object.assign(..), which is a simplified version of these algorithms. The first argument is the target, and any other arguments passed are the sources, which will be processed in listed order. For each source, its enumerable and own (e.g., not “inherited”) keys, including symbols, are copied as if by plain = assignment. Object.assign(..) returns the target object.

Consider this object setup:

  1. var target = {},
  2. o1 = { a: 1 }, o2 = { b: 2 },
  3. o3 = { c: 3 }, o4 = { d: 4 };
  4. // setup read-only property
  5. Object.defineProperty( o3, "e", {
  6. value: 5,
  7. enumerable: true,
  8. writable: false,
  9. configurable: false
  10. } );
  11. // setup non-enumerable property
  12. Object.defineProperty( o3, "f", {
  13. value: 6,
  14. enumerable: false
  15. } );
  16. o3[ Symbol( "g" ) ] = 7;
  17. // setup non-enumerable symbol
  18. Object.defineProperty( o3, Symbol( "h" ), {
  19. value: 8,
  20. enumerable: false
  21. } );
  22. Object.setPrototypeOf( o3, o4 );

Only the properties a, b, c, e, and Symbol("g") will be copied to target:

  1. Object.assign( target, o1, o2, o3 );
  2. target.a; // 1
  3. target.b; // 2
  4. target.c; // 3
  5. Object.getOwnPropertyDescriptor( target, "e" );
  6. // { value: 5, writable: true, enumerable: true,
  7. // configurable: true }
  8. Object.getOwnPropertySymbols( target );
  9. // [Symbol("g")]

The d, f, and Symbol("h") properties are omitted from copying; non-enumerable properties and non-owned properties are all excluded from the assignment. Also, e is copied as a normal property assignment, not duplicated as a read-only property.

In an earlier section, we showed using setPrototypeOf(..) to set up a [[Prototype]] relationship between an o2 and o1 object. There’s another form that leverages Object.assign(..):

  1. var o1 = {
  2. foo() { console.log( "foo" ); }
  3. };
  4. var o2 = Object.assign(
  5. Object.create( o1 ),
  6. {
  7. // .. o2's definition ..
  8. }
  9. );
  10. // delegates to `o1.foo()`
  11. o2.foo(); // foo

Note: Object.create(..) is the ES5 standard utility that creates an empty object that is [[Prototype]]-linked. See the this & Object Prototypes title of this series for more information.