Object extension

Posted by ns1025 on Sat, 06 Nov 2021 00:43:45 +0100

Object extension

Object is the most important data structure in JavaScript. ES6 has significantly upgraded it. This chapter introduces the changes of the data structure itself, and the next chapter introduces the new methods of object objects.

Concise representation of attributes

ES6 allows you to write variables and functions directly in braces as object properties and methods. Such writing is more concise.

const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}

// Equivalent to
const baz = {foo: foo};

In the above code, the variable foo is written directly in braces. At this time, the attribute name is the variable name, and the attribute value is the variable value. Here is another example.

function f(x, y) {
  return {x, y};
}

// Equivalent to

function f(x, y) {
  return {x: x, y: y};
}

f(1, 2) // Object {x: 1, y: 2}

In addition to attribute shorthand, methods can also be shorthand.

const o = {
  method() {
    return "Hello!";
  }
};

// Equivalent to

const o = {
  method: function() {
    return "Hello!";
  }
};

The following is a practical example.

let birth = '2000/01/01';

const Person = {

  name: 'Zhang San',

  //Equivalent to birth: birth
  birth,

  // Equivalent to hello: function()
  hello() { console.log('My name is', this.name); }

};

This writing method is very convenient for the return value of a function.

function getPoint() {
  const x = 1;
  const y = 10;
  return {x, y};
}

getPoint()
// {x:1, y:10}

In fact, the setter and getter of attributes are written in this way.

let girl = {
    _age : 18,
    get age(){
        return "I would not tell you.!"
    },
    set age(v){
        if (v > 18){
            this._age = 18
        }else{
            this.age = v
        }
    }
}


console.log(girl.age);
girl.age = 28
console.log(girl.age)
console.log(girl._age);

Concise writing is also useful when printing objects.

let user = {
  name: 'test'
};

let foo = {
  bar: 'baz'
};

console.log(user, foo)
// {name: "test"} {bar: "baz"}
console.log({user, foo})
// {user: {name: "test"}, foo: {bar: "baz"}}

In the above code, when console.log directly outputs user and foo objects, they are two sets of key value pairs, which may be confused. Put them in curly braces and output them, which becomes a concise representation of the object. The object name will be printed in front of each group of key value pairs, which is more clear.

super keyword

As we know, this keyword always points to the current object where the function is located. ES6 adds another similar keyword super to point to the prototype object of the current object.

let cell = {
    name : "Unicellular organism"
}

let person = {
    name : "human beings",
    ancestor () {
        return super.name
    }
}
// Set the prototype of the person object to cell
Object.setPrototypeOf(person,cell)

console.log(person.name);
console.log(person.ancestor());//Unicellular organism

In the above code, the name attribute of the prototype object cell is referenced through super.name in the person. Ancester () method of the object.

Note that when the super keyword represents a prototype object, it can only be used in the method of the object, and an error will be reported elsewhere.

// report errors
const obj = {
  foo: super.foo
}

// report errors
const obj = {
  foo: () => super.foo
}

// report errors
const obj = {
  foo: function () {
    return super.foo
  }
}

The above three super usages will report errors, because for JavaScript engines, none of the super here is used in object methods. The first method is to use super in the attribute. The second and third methods are to use super in a function and assign it to the foo attribute. At present, only the abbreviation of object method can let the JavaScript engine confirm that it defines the method of object.

New method of object

Object.assign()

Basic Usage

The Object.assign() method is used to merge objects and copy all enumerable attributes of the source object (source) to the target object (target).

const target = { a: 1 };

const source1 = { b: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

The first parameter of the Object.assign() method is the target object, and the following parameters are the source object.

Note that if the target object has a property with the same name as the source object, or multiple source objects have a property with the same name, the subsequent property will overwrite the previous property.

const target = { a: 1, b: 1 };

const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

Attention

(1) Shallow copy

The Object.assign() method implements a shallow copy, not a deep copy. That is, if the value of an attribute of the source object is an object, the target object copies the reference of the object.

const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);

obj1.a.b = 2;
obj2.a.b // 2

In the above code, the value of the a attribute of the source object obj1 is an object, and the reference of this object is copied by Object.assign(). Any changes to this object will be reflected on the target object.

(2) Replacement of attributes with the same name

For such nested objects, once an attribute with the same name is encountered, the processing method of Object.assign() is to replace rather than add.

const target = { a: { b: 'c', d: 'e' } }
const source = { a: { b: 'hello' } }
Object.assign(target, source)
// { a: { b: 'hello' } }

In the above code, the a attribute of the target object is completely replaced by the a attribute of the source object without the result of {A: {B: 'hello', D: 'e'}}. This is usually not what developers want and requires special care.

Object.keys(),Object.values(),Object.entries()

Object.keys()

ES5 introduces the Object.keys method, which returns an array. The members are the key names of all the enumerable properties of the parameter object itself (excluding inheritance).

var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]

ES2017 introduce Object.values and Object.entries, which are matched with Object.keys, are used as supplementary means to traverse an object for the for...of loop.

let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };

for (let key of keys(obj)) {
  console.log(key); // 'a', 'b', 'c'
}

for (let value of values(obj)) {
  console.log(value); // 1, 2, 3
}

for (let [key, value] of entries(obj)) {
  console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}

Object.values()

The Object.values method returns an array whose members are the key values of all enumerable properties of the parameter object itself (excluding inheritance).

const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]

The member order of the returned array is consistent with the arrangement rules described in the traversal of attributes in this chapter.

const obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
// ["b", "c", "a"]

In the above code, the attribute named value is traversed from small to large according to the value, so the return order is b, c and a.

Object.values filters the attribute named Symbol value.

Object.values({ [Symbol()]: 123, foo: 'abc' });
// ['abc']

If the parameter of the Object.values method is a string, an array of characters will be returned.

Object.values('foo')
// ['f', 'o', 'o']

In the above code, the string will first be converted into an array like object. Each character of the string is an attribute of the object. Therefore, Object.values returns the key value of each attribute, which is an array of characters.

If the parameter is not an object, Object.values first converts it to an object. Because of the wrapper objects of numeric and Boolean values, non inherited properties are not added to the instance. Therefore, object. Values returns an empty array.

Object.values(42) // []
Object.values(true) // []

Object.entries()

The Object.entries() method returns an array whose members are an array of key value pairs of all the enumerable properties of the parameter object itself (excluding inheritance).

const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]

Except that the return value is different, the behavior of this method is basically the same as that of Object.values.

If the property name of the original object is a Symbol value, the property is ignored.

Object.entries({ [Symbol()]: 123, foo: 'abc' });
// [ [ 'foo', 'abc' ] ]

In the above code, the original object has two attributes. Object.entries only outputs attributes with attribute names other than Symbol values. In the future, there may be a Reflect.ownEntries() method that returns all the properties of the object itself.

The basic purpose of Object.entries is to traverse the properties of an object.

let obj = { one: 1, two: 2 };
for (let [k, v] of Object.entries(obj)) {
  console.log(
    k,v
  );
}
// "one": 1
// "two": 2

Another use of the Object.entries method is to turn the object into a real Map structure.

const obj = { foo: 'bar', baz: 42 };
const map = new Map(Object.entries(obj));
map // Map { foo: "bar", baz: 42 }

Implement the Object.entries method yourself, which is very simple.

// Version of the Generator function
function* entries(obj) {
  for (let key of Object.keys(obj)) {
    yield [key, obj[key]];
  }
}

// Version of non Generator function
function entries(obj) {
  let arr = [];
  for (let key of Object.keys(obj)) {
    arr.push([key, obj[key]]);
  }
  return arr;
}

Object.fromEntries()

The Object.fromEntries() method is the inverse operation of Object.entries(), which is used to convert a key value pair array into an object.

Object.fromEntries([
  ['foo', 'bar'],
  ['baz', 42]
])
// { foo: "bar", baz: 42 }

The main purpose of this method is to restore the data structure of key value pairs to objects, so it is particularly suitable to convert the Map structure to objects.

// Example 1
const entries = new Map([
  ['foo', 'bar'],
  ['baz', 42]
]);

Object.fromEntries(entries)
// { foo: "bar", baz: 42 }

// Example 2
const map = new Map().set('foo', true).set('bar', false);
Object.fromEntries(map)
// { foo: true, bar: false }

Topics: Javascript ECMAScript