// === Arrays | |
var [a, b] = [1, 2]; | |
console.log(a, b); | |
//=> 1 2 | |
// Use from functions, only select from pattern | |
var foo = () => [1, 2, 3]; | |
var [a, b] = foo(); | |
console.log(a, b); | |
// => 1 2 | |
// Omit certain values | |
var [a, , b] = [1, 2, 3]; | |
console.log(a, b); | |
// => 1 3 | |
// Combine with spread/rest operator (accumulates the rest of the values) | |
var [a, ...b] = [1, 2, 3]; | |
console.log(a, b); | |
// => 1 [ 2, 3 ] | |
// Fail-safe. | |
var [, , , a, b] = [1, 2, 3]; | |
console.log(a, b); | |
// => undefined undefined | |
// Swap variables easily without temp | |
var a = 1, b = 2; | |
[b, a] = [a, b]; | |
console.log(a, b); | |
// => 2 1 | |
// Advance deep arrays | |
var [a, [b, [c, d]]] = [1, [2, [[[3, 4], 5], 6]]]; | |
console.log("a:", a, "b:", b, "c:", c, "d:", d); | |
// => a: 1 b: 2 c: [ [ 3, 4 ], 5 ] d: 6 | |
// === Objects | |
var {user: x} = {user: 5}; | |
console.log(x); | |
// => 5 | |
// Fail-safe | |
var {user: x} = {user2: 5}; | |
console.log(x); | |
// => undefined | |
// More values | |
var {prop: x, prop2: y} = {prop: 5, prop2: 10}; | |
console.log(x, y); | |
// => 5 10 | |
// Short-hand syntax | |
var { prop, prop2} = {prop: 5, prop2: 10}; | |
console.log(prop, prop2); | |
// => 5 10 | |
// Equal to: | |
var { prop: prop, prop2: prop2} = {prop: 5, prop2: 10}; | |
console.log(prop, prop2); | |
// => 5 10 | |
// === Potential grammar hiccups | |
// Oops: This doesn't work: | |
var a, b; | |
{ a, b } = {a: 1, b: 2}; | |
// But this does work | |
var a, b; | |
({ a, b } = {a: 1, b: 2}); | |
console.log(a, b); | |
// => 1 2 | |
// This due to the grammar in JS. | |
// Starting with { implies a block scope, not an object literal. | |
// () converts to an expression. | |
// From Harmony Wiki: | |
// Note that object literals cannot appear in | |
// statement positions, so a plain object | |
// destructuring assignment statement | |
// { x } = y must be parenthesized either | |
// as ({ x } = y) or ({ x }) = y. | |
// === Combined destructuring of objects and arrays | |
// Combine objects and arrays | |
var {prop: x, prop2: [, y]} = {prop: 5, prop2: [10, 100]}; | |
console.log(x, y); | |
// => 5 100 | |
// === Nested object destructuring | |
// Deep objects | |
var { | |
prop: x, | |
prop2: { | |
prop2: { | |
nested: [ , , b] | |
} | |
} | |
} = { prop: "Hello", prop2: { prop2: { nested: ["a", "b", "c"]}}}; | |
console.log(x, b); | |
// => Hello c | |
// === Combining all to make fun happen | |
// All well and good, can we do more? Yes! | |
// Using as method parameters | |
var foo = function ({prop: x}) { | |
console.log(x); | |
}; | |
foo({invalid: 1}); | |
foo({prop: 1}); | |
// => undefined | |
// => 1 | |
// === Nested advanced examples | |
// Can also use with the advanced example | |
var foo = function ({ | |
prop: x, | |
prop2: { | |
prop2: { | |
nested: b | |
} | |
} | |
}) { | |
console.log(x, ...b); | |
}; | |
foo({ prop: "Hello", prop2: { prop2: { nested: ["a", "b", "c"]}}}); | |
// => Hello a b c | |
// === In combination with other ES2015 features. | |
// Computed property names | |
const name = 'fieldName'; | |
const computedObject = { [name]: name }; // (where object is { 'fieldName': 'fieldName' }) | |
const { [name]: nameValue } = computedObject; | |
console.log(nameValue) | |
// => fieldName | |
// === Rest and defaults | |
var ajax = function ({ url = "localhost", port: p = 80}, ...data) { | |
console.log("Url:", url, "Port:", p, "Rest:", data); | |
}; | |
ajax({ url: "someHost" }, "additional", "data", "hello"); | |
// => Url: someHost Port: 80 Rest: [ 'additional', 'data', 'hello' ] | |
ajax({ }, "additional", "data", "hello"); | |
// => Url: localhost Port: 80 Rest: [ 'additional', 'data', 'hello' ] | |
ajax({ }); | |
// => Url: localhost Port: 80 Rest: [] | |
// Doesn't work due to trying to destructure undefined | |
ajax(); | |
// => Uncaught TypeError: Cannot match against 'undefined' or 'null' | |
// To fix this we need to have default value for parameter in function | |
// Note: See the `= {}` at the end, saying default empty object if the first argument is undefined. | |
var ajax = ({ url: url = "localhost", port: p = 80} = {}) => { | |
console.log("Url:", url, "Port:", p); | |
}; | |
// Now this works. | |
ajax(); | |
// => Url: localhost Port: 80 | |
ajax({ }); | |
// => Url: localhost Port: 80 | |
ajax({ port: 8080 }); | |
// => Url: localhost Port: 8080 | |
ajax({ url: "someHost", port: 8080 }); | |
// => Url: someHost Port: 8080 | |
// === Similar to _.pluck | |
var users = [ | |
{ user: "Name1" }, | |
{ user: "Name2" }, | |
{ user: "Name2" }, | |
{ user: "Name3" } | |
]; | |
var names = users.map( ({ user }) => user ); | |
console.log(names); | |
// => [ 'Name1', 'Name2', 'Name2', 'Name3' ] | |
// === Usage in for..of loops | |
var users = [ | |
{ user: "Name1" }, | |
{ user: "Name2", age: 2 }, | |
{ user: "Name2" }, | |
{ user: "Name3", age: 4 } | |
]; | |
for (let { user, age = "DEFAULT AGE" } of users) { | |
console.log(user, age); | |
} | |
// => Name1 DEFAULT AGE | |
// => Name2 2 | |
// => Name2 DEFAULT AGE | |
// => Name3 4 |
This comment has been minimized.
This comment has been minimized.
Thanks .. |
This comment has been minimized.
This comment has been minimized.
Nice. That js grammar issue is easy to explain with arrow functions:
|
This comment has been minimized.
This comment has been minimized.
awesome. |
This comment has been minimized.
This comment has been minimized.
Here are slides with runnable demos and edit features from the talk where these examples originated: http://git.mikaelb.net/presentations/bartjs/destructuring |
This comment has been minimized.
This comment has been minimized.
How about
|
This comment has been minimized.
This comment has been minimized.
@gilesbradshaw Ah, a combination of variable property name and destructuring. I like that. Never thought of combining it. Adding it now |
This comment has been minimized.
This comment has been minimized.
glad you like it :) |
This comment has been minimized.
This comment has been minimized.
Manual pull request: Use Arrow Function Shorthand: -var foo = () => {
- return [1, 2, 3];
-};
+var foo = () => [1, 2, 3]; |
This comment has been minimized.
This comment has been minimized.
Updated. Didn't really have to be a fat arrow in that case, but just as well. |
This comment has been minimized.
This comment has been minimized.
Good read. :) [
{ firstName: "Paul", lastName: "Nicklen", age: 48, profession: "Photography"},
{ firstName: "Steve", lastName: "McCurry", age: 66, profession: "Photography"},
{ firstName: "Frans", lastName: "Lanting", age: 65, profession: "Photography"},
{ firstName: "Jimmy", lastName: "Chinn", age: 42, profession: "Photography"}
].map(({firstName, lastName, age}) => ({name:firstName + lastName, age})); |
This comment has been minimized.
This comment has been minimized.
Super Helpful! Thanks! |
This comment has been minimized.
This comment has been minimized.
great work! |
This comment has been minimized.
This comment has been minimized.
You may also want to demonstrate destructuring with default function parameters. var ajax = ({ url: url = "localhost", port: p = 80} = {}) => {
console.log("Url:", url, "Port:", p);
};
ajax();
// => Url: localhost Port: 80
ajax({ port: 8080 });
// => Url: localhost Port: 8080
ajax({ url: "someHost", port: 8080 });
// => Url: someHost Port: 8080 |
This comment has been minimized.
This comment has been minimized.
@iczechowski I updated the destructure function parameter section now to be more clear. Thanks! |
This comment has been minimized.
This comment has been minimized.
Hi @mikaelbr can I ask something? Thank you in advance |
This comment has been minimized.
This comment has been minimized.
Additionally in the last example I tried it without brackets and works fine |
This comment has been minimized.
This comment has been minimized.
Hi @ariel2023. Sorry for the late response, but I don't get notifications from gists. I don't understand what you mean about the first example you get: var { prop: x, prop2: [, y] } = { prop: 5, prop2: [10, 100] }; Here you do "name var { prop: x, prop2: [, y] } = { prop: 5, prop2: [10, 100]};
console.log({ x, y });
//=> Result: Object {x: 5, y: 100} As for the second example, this can probably removed. The example was written at a time where So writing the example using those constructs instead we could do: var users = [
{ user: "Name1" },
{ user: "Name2", age: 2 },
{ user: "Name2" },
{ user: "Name3", age: 4 }
];
users.forEach(({ user, age = "DEFAULT AGE" }) => console.log(user, age)); As a sidenote: It works when you remove the for ({ user, age = "DEFAULT AGE" } of users) console.log(user, age); becomes for ({ user, age = "DEFAULT AGE" } of users) {
console.log(user, age);
} Which is destructuring user, age from users each iteration and printing that. Please note, though, this wouldn't work in strict mode. As we are not declaring our variables before using them in the destructuring. For it to be valid we would have to do something like: for (let { user, age = "DEFAULT AGE" } of users) {
console.log(user, age);
} |
This comment has been minimized.
This comment has been minimized.
I did something like this, let str = "hello";
const toCapital = ([a, ...b]) => [a.toUpperCase(), ...b].join('');
console.log(toCapital(str)); // Hello and it works! |
This comment has been minimized.
This comment has been minimized.
@reoxb In JavaScript, you can iterate strings, as it is a sequence of characters. See for instance: console.log("Hello"[0]); //=> 'H' Also you can get the iterator from a string, as you can with an array: "Hello"[Symbol.iterator] // Returns the iterator. e.g. for (let l of "hello")
console.log(l); |
This comment has been minimized.
This comment has been minimized.
Dummy question |
This comment has been minimized.
This comment has been minimized.
@asicfr I'm afraid you can't by using default parameter. Technically, Now you could always write a decorator for a function to convert function undefinedNull (fn) {
return function (...args) {
return fn(...args.map(v => v == null ? void 0 : v));
};
}
let add = undefinedNull(function (a = 5, b = 3) {
return a + b;
});
add(); //=> 8
add(undefined, null); //=> 8
add(null, null); //=> 8
add(2, 2); //=> 4 I'd say avoiding |
This comment has been minimized.
This comment has been minimized.
yes, i think you're right. |
This comment has been minimized.
This comment has been minimized.
wow nice gist!
I would compare |
This comment has been minimized.
This comment has been minimized.
thanks for sharing :D wasn't sure about nested destructuring..now I know |
This comment has been minimized.
This comment has been minimized.
Please note, that now you can use variable as key: {
const key = 'user';
const { [key]: x } = { user: 5 };
console.log(x);
// 5
} |
This comment has been minimized.
This comment has been minimized.
Thank you |
This comment has been minimized.
This comment has been minimized.
How would you use array destructuring in a
(Ignore the test suite syntax. How do I rewrite the |
This comment has been minimized.
This comment has been minimized.
@gitasong There are a couple of non-destructuring grammar rules in play in your example, I'm just going to explain some of them to avoid potential misunderstandings for other potential readers. When we iterate and use for (var a of [1, 2, 3]) {}
console.log(a); // Output: 3 As this is essentially the same as: var a;
a = 1;
a = 2;
a = 3;
console.log(a); // Output: 3 This would not be the case if we used for (let z of [1, 2, 3]) {}
console.log(z); // z is not defined This explains why we can use for (var [a, b] of [[0, 1, 2]]) Says for each iteration, take the current item (in this case it's only one item, // instead of something like
for (var [a, b] of [[0, 1, 2], [3, 4, 5]]) console.log(a, b);
// it would be
var a, b;
[a, b] = [0, 1, 2];
console.log(a, b); // 0 1
[a, b] = [3, 4, 5];
console.log(a, b); // 3 4 From this, we can also see that the destructuring part of it is a normal array destructuring. And seeing the gist above, we can omit values in destructuring by not having an identifier. Meaning, we can ignore the first value in the array (the var a, b;
[ , a, b] = [0, 1, 2];
// ^--- note the comma. Ignoring the first item
console.log(a, b); // Output: 1 2 This was a very long winded and maybe too detailed explanation, but I hope it gives somewhat more insight. The short version is that you can ignore elements in destructuring by using no identifiers, and making your test pass by doing: it('in for-of loop', () => {
for (var [, a, b] of [[0, 1, 2]]) {}
expect([a, b]).toEqual([1, 2]);
}); Hope this helps. |
This comment has been minimized.
This comment has been minimized.
This is handy when you want to destructure and redefine. Hat-trick! function foo(param) {
const arg = {a, b} = param
console.log(a, b)
console.log(arg)
}
foo({a:1, b:2}) |
This comment has been minimized.
This comment has been minimized.
+1 |
This comment has been minimized.
This comment has been minimized.
can I set like
// in store.js
// in component
|
This comment has been minimized.
This comment has been minimized.
@mqliutie I'm not entirely sure if I understand the question. Are you talking about constructing objects after destructuring it? Could you maybe show a more concise example? |
This comment has been minimized.
This comment has been minimized.
how about:
why is the output |
This comment has been minimized.
This comment has been minimized.
@evandrix If I understand the question correctly, the key here is the destructuring of arrays. Let's simplify the code to see only the relevant parts: const data = [{
item: 'Awesome shoe',
price: 19.99,
inStore: ['Regent Street', 'Oxford Street', 'Harrods']
}, {
item: 'Fave shirt',
price: 12.99,
inStore: ['Regent Street']
}];
const [ { item, inStore: [, , x] } ] = data;
console.log(item + " is in " + x); Which would result in the same. We can reduce the structure further if we just focus on the item and not the const data = [{
item: 'Awesome shoe'
}, {
item: 'Fave shirt'
}];
const [ { item } ] = data;
console.log(item); //=> Awesome shoe And that again is pretty much the same as: const data = [1, 2];
const [ item ] = data;
console.log(item); //=> 1 And hopefully it's easier to see what is going on. We're destructuring an array and fetching the first element and ignore all other in the array. As if we did |
This comment has been minimized.
This comment has been minimized.
Thanks! I'm using it production now. |
This comment has been minimized.
This comment has been minimized.
Thank you! Another one I find nifty when iterating objects and requiring both the keys and values: Object.entries({x: "xval", y: "yval"}).map(([key, val]) => console.log(key, val));
// x xval
// y yval |
This comment has been minimized.
This comment has been minimized.
Thank You! I was looking for a way to do this but it wasn't obvious to me that this particular approach would actually work: const {prop01, prop01: { prop10 }} = {prop00: 0, prop01: {prop10: 10, prop11: 11}}
console.log(prop01, prop10)
// => {prop10: 10, prop11: 11} 10
// Example use case:
// const { request, request: { url }} = event |
This comment has been minimized.
This comment has been minimized.
... Let's simplify the code to see only the relevant parts:
@mikaelbr - Very helpful, great explanation. Thank you!!! |
This comment has been minimized.
This comment has been minimized.
@mikaelbr, thanks, this is fantastic... ...but I have a question. I will keep it as brief as possible, so there will be a lot of ...
// ...
// myFileContents contains ..."firstArg": "split\nline",...
const myJSON = JSON.parse(myFileContents);
class myClassDoesSomeStuff {
constructor (someArgs = {}) {
const {
firstArg = '',
secondArg = '',
// etc.
...
} = someArgs;
console.log(firstArg)
// ...
let someObject = new myClassDoesSomeStuff(myJSON); firstArg is printed as
not as
to get around this, I end up doing
But that feels really gross, an ugly hack (but neither rude nor evil, so I can live with). Is there a more elegant solution? Thanks! |
This comment has been minimized.
This comment has been minimized.
I realized there is an error in my "sample code", the use of console.log, which will print out the newline no matter what:
In my actual code, values like firstArg are being assigned to a DOM element (a text input box). Without my stringify...replace trick, the \n gets converted, but with it, it is preserved, which is what I want. Sorry for the confusion. |
This comment has been minimized.
This comment has been minimized.
Hi, @PeterWhittaker! I don't know if I understand your problem correctly, but when you have a newline character like this, But in input textarea (note Again, I don't really understand your problem. But if you wanted to keep the actual newline character inside your input field, without using textarea. You would have to "escape it". By escaping |
This comment has been minimized.
This comment has been minimized.
We’re close! I don’t want the new line, I want the \n preserved as two
characters. By doing the stringify trick, I preserve those two characters
and they appear in the text field, which is what I want.
Without the stringify trick, the two characters are converted to a newline,
and lost as white space.
So it’s working the way I want but using stringify feels like a hack - it
feels like there should be a cleaner way to preserve the \n all the way
through.
|
This comment has been minimized.
This comment has been minimized.
Read the last part of my comment above on escaping. If you want to keep |
This comment has been minimized.
This comment has been minimized.
I think we're at cross-purposes a little, as I did mention that I was
escaping, but was wondering whether there was a more elegant way to do it
than the option I opted for - as it turns out, there isn't, really,
JSON.stringify(...).replace(...) is pretty much the easiest, most robust
approach, and has to be sometime, somewhere before assigning to the DOM -
it isn't necessary within JS itself.
The issue isn't in the JS itself, since within the JS, \n gets preserved in
the string right up until it is assigned to a DOM element, as seen in
https://jsfiddle.net/am392d6f/
tl;dr, when assigning to the DOM, the string must be protected against
interpretation - yes, this is escaping, but not where I thought it was
needed:
- anElement.value = "some\nline"; //doesn't work, \n is lost
- anElement.value = "some\\nline"; //works
- anElement.value = (JSON.stringify("some\nline").replace(/^"|"$/g, ''); // works
Thanks for your patience, I initially thought this was a problem with how I
was destructuring, but destructuring, object.assign(), and straight string
passing all have the same results (that's nice at least): Everything is
fine within JS, the problem comes when assigning to the DOM, which is
essentially an output operation, as I realize now.
|
This comment has been minimized.
awesome examples!
really useful feature...