38

Is there a performance difference, if any, between writing

const color = props.color;

vs

const { color } = props;

Also, do we gain or lose any performance if we destructure in the parameters signature? See example3

I assume example3 in this situation would be the best way to write the function?


Example functional react components:

const example1 = (props) => {
  const color = props.color;
  // I know I could also just write style={{ color: props.color }}
  // but for arguments sake lets say I want to write it like this.
  return <h1 style={{ color }}>Hello</h1>;
};

const example2 = (props) => {
  const { color } = props;
  return <h1 style={{ color }}>Hello</h1>;
};

const example3 = ({ color }) => {
  return <h1 style={{ color }}>Hello</h1>;
};
8
  • 7
    Bearing in mind that you're using JSX, so your code is being transpiled before being run, it's quite likely that all three of these result in very similar/identical code. Commented Nov 3, 2017 at 15:41
  • 6
    best to google js perf {feature} most of the time to get the answer... see jsperf.com/destructuring/5 Commented Nov 3, 2017 at 15:41
  • 9
    The general answer is: "It depends, and may be faster or slower or the same. But it extremely unlikely to make a real-world difference; don't worry about it until/unless you identify a problem and find that it's related to X." (where X is the thing you were worrying about prematurely). Commented Nov 3, 2017 at 15:44
  • 3
    The answer to questions like this is ALWAYS the same. Test yourself in whatever Javascript environment you care about right now. Then, don't assume that test result applies to any other Javascript environment either now or a year from now. This stuff is often different in every environment and changes with time. If you're micro-optimizing a statement for performance in a particular environment, you have to develop your own tests to see what works best for you. And, before you spend any time doing that, you should prove to yourself that a difference would actually matter. Commented Nov 3, 2017 at 15:45
  • 9
    This is one of the things you should optimise for readability instead of making premature microoptimisations for speed. Commented Nov 3, 2017 at 15:52

4 Answers 4

40

It's not necessarily true that a compiler/transpiler will always remove destructuring assignments as all evergreen browsers support destructuring natively as of 2020. As per, there is some evidence that as of at least 2018 the bytecode generated in V8 by a destructuring assignment is much more verbose than traditional function parameters:

Function Parameters:

function add(number1, number2){
  return number1 + number2;
}
const result = add(1,5);

Output bytecode:

[generating bytecode for function: add]
Parameter count 3
Frame size 0
   74 E> 0x2a2a0affd2a2 @    0 : 91                StackCheck 
   96 S> 0x2a2a0affd2a3 @    1 : 1d 02             Ldar a1
  111 E> 0x2a2a0affd2a5 @    3 : 2b 03 00          Add a0, [0]
  121 S> 0x2a2a0affd2a8 @    6 : 95                Return 
Constant pool (size = 0)
Handler Table (size = 16)

Destructured Assignment:

function add({number1, number2}){
  return number1 + number2;
}
const result = add({number1: 1, number2: 5});

Output Bytecode:

[generating bytecode for function: add]
Parameter count 2
Frame size 40
   74 E> 0x2c1d63b7d312 @    0 : 91                StackCheck 
         0x2c1d63b7d313 @    1 : 1f 02 fb          Mov a0, r0
         0x2c1d63b7d316 @    4 : 1d fb             Ldar r0
         0x2c1d63b7d318 @    6 : 89 06             JumpIfUndefined [6] (0x2c1d63b7d31e @ 12)
         0x2c1d63b7d31a @    8 : 1d fb             Ldar r0
         0x2c1d63b7d31c @   10 : 88 10             JumpIfNotNull [16] (0x2c1d63b7d32c @ 26)
         0x2c1d63b7d31e @   12 : 03 3f             LdaSmi [63]
         0x2c1d63b7d320 @   14 : 1e f8             Star r3
         0x2c1d63b7d322 @   16 : 09 00             LdaConstant [0]
         0x2c1d63b7d324 @   18 : 1e f7             Star r4
         0x2c1d63b7d326 @   20 : 53 e8 00 f8 02    CallRuntime [NewTypeError], r3-r4
   76 E> 0x2c1d63b7d32b @   25 : 93                Throw 
   76 S> 0x2c1d63b7d32c @   26 : 20 fb 00 02       LdaNamedProperty r0, [0], [2]
         0x2c1d63b7d330 @   30 : 1e fa             Star r1
   85 S> 0x2c1d63b7d332 @   32 : 20 fb 01 04       LdaNamedProperty r0, [1], [4]
         0x2c1d63b7d336 @   36 : 1e f9             Star r2
   98 S> 0x2c1d63b7d338 @   38 : 1d f9             Ldar r2
  113 E> 0x2c1d63b7d33a @   40 : 2b fa 06          Add r1, [6]
  123 S> 0x2c1d63b7d33d @   43 : 95                Return 
Constant pool (size = 2)
Handler Table (size = 16)

The number of bytecode lines increased significantly from 4 in the case of function parameters to 19 in the case of the destructured assignment. In conclusion destructured assignments are less computationally efficient than traditional function parameters, as of 2018 in V8. In terms of memory space utilization the answer is a bit more complex and can be referenced here.

This could be a premature optimization however in compute heavy code it may be advisable to consider not using destructuring assignments.

Sign up to request clarification or add additional context in comments.

4 Comments

The performance difference between regular args and destructuring point stands, but the two functions being compared aren't equivalent to ops. function add(opts){ const number1 = opts.number1; const number2 = opts.number2; return number1 + number2; } would be the comparison
In v8 8.4.371.19-node.18 they end up the same and look a bit more terse now.
exactly the explanation i was looking for. Thank you
Does destructuring like that use heap space and cause garbage collection?
5

There won't be any performance issues as your code will be compiled/minify and so on.

Note that with React, your code will be transpiled which will do the same as

const color = props.color

Check the result on the babel compiler online tester

1 Comment

shows different output for both syntax at babel compiler. is this answer no longer valid?
0

Bundle size also matters in javascript performance, and destructuring variable has some caveats in some situations especially when they are function parameters.

First example WITHOUT object destructuring

function add(number1, number2){
  return number1 + number2;
}
const result = add(1,5);

// Result
function add(d,n){return d+n}const result=add(1,5);

Input: 86 bytes;Output: 51 bytes;Compression: 40.7%,saving: 35 bytes;

Second example WITH object destructuring

function add({number1, number2}){
  return number1 + number2;
}
const result = add({number1: 1, number2: 5});

// Result
function add({number1:n,number2:r}){return n+r}
const result=add({number1:1,number2:5});

Input: 109 bytes;Output: 87 bytes;Compression: 20.18%,saving: 22 bytes;

Third example, using object but no destructuring

function add(opts){ 
  const number1 = opts.number1; 
  const number2 = opts.number2; 
  return number1 + number2; 
}

add({number1: 1, number2:5});

// Result
function add(n){return n.number1+n.number2}add({number1:1,number2:5});

Input: 148 bytes;Output: 70 bytes;Compression: 52.7%,saving: 78 bytes;

Conclusion

In all situations, object destructuring is the worst bundle size because it can't optimize the names of the objects (maybe there is an option that I forgot). My personal opinion would be to focus on maintainability and therefore readability. I have the feeling that these micro improvements are not worth it if you make your code worse.

BONUS: variable instantiation (out of scope)

In some situations, object destructuring is better from the bundle size point of view. When you initialize variables.

No object destructuring

const obj = {username:"name",lastname:"lastname",age:20};
console.log('break minify optimization');
const username = obj.username;
const lastname = obj.lastname;
const age = obj.age;

// Result
const obj={username:"name",lastname:"lastname",age:20};console.log("break minify optimization");const username=obj.username,lastname=obj.lastname,age=obj.age;

Input: 182 bytes; Output: 158 bytes; Compression: 13.19%, saving: 24 bytes;

With object destructuring

const obj = {username:"name",lastname:"lastname",age:20};
console.log('break minify optimization');
const {username, lastname, age} = obj;

// Result
const obj={username:"name",lastname:"lastname",age:20};console.log("break minify optimization");const{username,lastname,age}=obj;

Input: 138 bytes; Output: 129 bytes; Compression: 6.52%, saving: 9 bytes;

Thanks

Without the answers from nikk wong and Matt I wouldn't have been gone that far in my explanations, up vote their answers too :)

Any feedback is welcome.

Comments

-2

I wondered the same. I suppose destructing would consume more memory. While accessing object properties or array elements through their reference, we are accessing the same memory location. When an object or array is destructured, if the values are primitives, the values are copied into a new location. So, destructuring does consumes more memory than accessing through object properties.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.