hijiangtao
hijiangtao

Reputation: 903

What properties will rest skip in Object Destructuring?

I am using rest parameter to do some operations, but got some properties disappeared in result.

The data format of this.props looks like this:

```
this.props = {
  data: [{...}, ...],
  ...
}
```

And I tried to rest it in this way:

```
let {showWaveAnimation, ...otherProps} = this.props;

console.log('data' in otherProps); // false
console.log('data' in this.props); //true
```

Why would 'data' property lost after I tried rest operation?

According to MDN, I found the description:

rest parameters are only the ones that haven't been given a separate name (i.e. formally defined in function expression), while the arguments object contains all arguments passed to the function;

What does separate name here means? Is it means properties that extends from its prototype would not be rest? But after I tried the following statements, I got the same result, I am confusing.

```
class Parent {
    constructor() {
        this.props = {
            data: '123',
        };
    }
}

class Child extends Parent {
    constructor() {
        super();
        this.props.childProp = 'test';

        let {test, ...otherProps} = this.props;
        console.log('data' in this.props, 'data' in otherProps);
        // true true
    }
}

new Child();
```

The former code behaviors abnormal after Babel's transpiling, could it be Babel's plugin problem?

ADD: I found this concept may be more precise in describing my rest operations. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Rest_in_Object_Destructuring

Upvotes: 2

Views: 1245

Answers (3)

hijiangtao
hijiangtao

Reputation: 903

I figured out why 'data' disappeared in my rest result, it's the enumerable property of 'data' field!

Once, the property is set as enumerable: false, we can't get it with the operation of rest in object destructuring.

According to MDN

The Rest/Spread Properties for ECMAScript proposal (stage 3) adds the rest syntax to destructuring. Rest properties collect the remaining own enumerable property keys that are not already picked off by the destructuring pattern.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Rest_in_Object_Destructuring

I think this example can explain my ideas more precisely:

const person = {  
  name: 'Dave',
  surname: 'Bowman'
};

Object.defineProperty(person, 'age', {  
  enumerable: false, // Make the property non-enumerable
  value: 25
});
console.log(person['age']); // => 25

const clone = {  
  ...person
};
console.log(clone); // => { name: 'Dave', surname: 'Bowman' }

Upvotes: 1

Drew Reese
Drew Reese

Reputation: 202751

rest parameters are only the ones that haven't been given a separate name (i.e. formally defined in function expression), while the arguments object contains all arguments passed to the function;

What does separate name here means? Is it means properties that extends from its prototype would not be rest? But after I tried the following statements, I got the same result, I am confusing.

Given a function definition function foo(a, b, ...c) {}, arguments a, and b are the named parameters, whereas the rest of the passed arguments are spread into the last variable c. Now, c is a named variable, but any parameters passed from the third on will just be accessible in c, i.e. c[0].

Now, your console.log error is stemming from your use of the in operator. You defined an object const foo = {'data': 'bar'}. 'data' in foo is true, but 'blarg' in foo is false since foo doesn't contain a key/property named 'blarg'.

You're actually using the spread operator to destructure your props object into several named variables.

const object = {
  data: 'foo',
  other: 'bar',
  moreData: [1,2,3],
};

// Example usage of the spread operator
const { data, ...allTheRest} = object;  // data is destructured, other and moreData into allTheRest

console.log(data);
console.log(allTheRest);

// in operator
console.log('data' in object); // true
console.log('data' in allTheRest); // false
console.log('moreData' in allTheRest); // true

// This is an example of the rest operator
const foo = (...allTheArgs) => {
  allTheArgs.forEach(e => console.log(e));
}

foo(1,2,3); // all the args are collected into a single array variable in the function

const bar = (a, b, ...c) => {
  console.log(`a: ${a}`);
  console.log(`b: ${b}`);
  console.log(`c: ${c}`);
};

bar('this is first param', 42, 'foo', 'bar', '1', 2, 'stackoverflow');

Upvotes: 0

Ivan
Ivan

Reputation: 40658

The rest parameter allows you to get all the remaining attributes not already selected by identifier preceding it in the assignment.

  • Let's take a simple example:

const obj = {
  a: 1,
  b: 2,
  c: 3
}

const { a, ...rest } = obj;

console.log(a);
console.log(rest);

Above obj has a property named a so it is destructured from obj and assigned to the variable a, then all other properties are assigned in an object to rest.

  • However, what you have is more like:

const obj = {
  a: 1,
  b: 2,
  c: 3
}

const { d, ...rest } = obj;

console.log(d);
console.log(rest);

Here obj doesn't have a property named d. So it is destructured from obj as undefined and assgined to the variable a. Then all other properties not already assigned, i.e. a, b and c are given to rest.

In your code otherProps has the same properties as this.props, because object this.props doesn't have a property named test. In other words, in order to destructure an object you have to know its structure.

Upvotes: 0

Related Questions