35

I'd like to do something like this:

const vegetableColors = {corn: 'yellow', peas: 'green'};

const {*} = vegetableColors;

console.log(corn);// yellow
console.log(peas);// green

I can't seem to find or figure out how to do this but I really thought I had seen it done somewhere before! :P

NOTE: I'm using Babel with stage set to 0;

CONTEXT: I'm trying to be drier in JSX and not reference this.state or this.props everywhere. And also not have to keep adding properties to destructure if the data changes.

Resist Design
  • 4,133
  • 2
  • 18
  • 34
  • Please try to find where you've seen this before, i'd love to read that article – Bergi Aug 09 '15 at 19:26
  • 2
    Let's say you could do that. So, what would the next statement be? How would you write code that used the variables that popped out of such a declaration if you don't know in advance what their names are? – Pointy Aug 09 '15 at 19:27
  • @Pointy, The point would be that if you're using a utility library like underscore or ramda, you don't have continually return to the top of your file and edit the line where you import your functions by name every time you use a new one (or prepend `_.` or `R.` to every function call). – Jonah May 29 '16 at 23:01
  • @Jonah that sounds like a serious code smell. Polluting your namespace willy-nilly seems like a recipe for continual potential disaster. – Pointy May 29 '16 at 23:39
  • 1
    @Pointy, Are you saying it's impossible to be in a situation where you are acquainted with some utility library and just want to be able to use its functions? What if *you* wrote the library? What is this "potential disaster" exactly? That you forgot the library had some function called X? – Jonah May 29 '16 at 23:44
  • I'm not saying it's impossible to be in such a situation. I'm saying that it's a situation to strenuously avoid. Undetectable name collisions are a recipe for a really bad afternoon. – Pointy May 29 '16 at 23:50
  • In the modern world of package managers and automated updating systems, it can be a real issue. Note that `n.x` point releases can freely *add* APIs to a package, so long as they don't break older APIs. Adding something to an API can totally include adding completely new functionality. So you do an `npm update` and all of a sudden (or, worse, *not* all of a sudden) your stuff stops working. – Pointy May 29 '16 at 23:53
  • The point about package updates is a fair one. – Jonah May 30 '16 at 00:11

3 Answers3

24

I think you're looking for the with statement, it does exactly what you are asking for:

const vegetableColors = {corn: 'yellow', peas: 'green'};
with (vegetableColors) {
    console.log(corn);// yellow
    console.log(peas);// green
}

However, it is deprecated (in strict mode, which includes ES6 modules), for good reason.

destructure all properties into the current scope

You cannot in ES61. And that's a good thing. Be explicit about the variables you're introducing:

const {corn, peas} = vegetableColors;

Alternatively, you can extend the global object with Object.assign(global, vegetableColors) to put them in the global scope, but really, that's worse than a with statement.

1: … and while I don't know whether there is a draft to allow such things in ES7, I can tell you that any proposal will be nuked by the TC :-)

Community
  • 1
  • 1
Bergi
  • 513,640
  • 108
  • 821
  • 1,164
  • Actually I only remembered my older answer, and didn't think about `this` immediately either :-) – Bergi Aug 09 '15 at 19:51
  • 2
    I knew about `with` and I would never use that but it's exactly what I'm asking for... Crap! What was I thinking!? :P – Resist Design Aug 09 '15 at 19:51
  • 4
    I disagree that this is a good thing. Sure, it *might* be dangerous. It also might be just what a programmer wants to do. He should be able to make the choice himself. And it's not as if javascript, as a language, has taken a hard design stance against anything enabling you to shoot yourself in the foot. – Jonah May 29 '16 at 22:56
  • 1
    @Jonah: Strict mode *is* the design stance against foot-shooting and optimisation-preventing features :-) You still can use `with` if you want, it won't get dropped from the language (mostly for backwards-compatibility concerns though). – Bergi May 29 '16 at 23:01
  • Eh, I still think this would be a useful feature, but I can see the other side of the argument. In any case, `with` is not a "solution" imo, because now you have to wrap your entire module in `with` and add a level indentation, which is even worse than prepending the object name to every function call or importing everything by name at the top with destructuring. – Jonah May 29 '16 at 23:04
  • @Jonah: You can drop the module-enclosing indentation if you want to, especially if it's nested `with` statements. Or rewrite some custom import syntax to a `with` statement as part of your build step if you can't see it at all. However, the indentation may actually work well as a reminder that you are in an unsafe scope. – Bergi May 29 '16 at 23:07
  • Well, if I care enough about this to use a build step, I think I'd rather just automatically generate the object destructuring import statement based on the functions being used and the required objects. It wouldn't be too hard. But, I think I don't care that much :) – Jonah May 29 '16 at 23:11
3

I think you're looking for:

const {corn, peas} = vegetableColors;

Live on Babel's REPL


If Pointy's right that you're asking how to do this without knowing the names corn and peas, you can't with destructuring assignment.

You can at global scope only, using a loop, but I'm sure you don't want to do this at global scope. Still, just in case:

// I'm sure you don't really want this, just being thorough
Object.keys(vegetableColors).forEach((key) => {
    Object.defineProperty(this, key, {
        value: vegetableColors[key]
    });
});

(Throw enumerable: true on there if you want these pseudo-constants to be enumerable.)

That works at global scope because this refers to the global object.

StudioTime
  • 18,874
  • 30
  • 103
  • 186
T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • 1
    I *think* what the OP is looking for is a way to unpack the properties of an object into like-named local variables without any foreknowledge of the source object. (I can't imagine what the use of that would be.) – Pointy Aug 09 '15 at 19:26
  • @Pointy: I added a context to the question just for you :) – Resist Design Aug 09 '15 at 19:47
  • 4
    Or maybe you want to unpack 100 properties without having to explicitly name them all and without having to update the list every time a new property is added to the object. – Moss May 01 '20 at 19:01
2

I wouldn't recommend it, but you can use eval() to accomplish something similar:

vegetableColors = {corn: 'yellow', peas: 'green'};

function test() {
    for ( let i=0; i < Object.keys(vegetableColors).length; i++ ) {
        let k = Object.keys(vegetableColors)[i];
        eval(`var ${k} = vegetableColors['${k}']`);
    }

    console.log(corn); // yellow
}

test();

console.log(corn); // undefined (out of scope)
kmoser
  • 5,337
  • 2
  • 18
  • 30