0

I wrote a simple object destructuring function that declares variables in given scope through assigning properties to the scope object

Can I use this function in production and if not what are the pitfalls of using such a function?

function destructure(obj, scope) {
  scope = scope || this;
  Object.keys(obj).forEach(key => {
    if (scope[key] === undefined) {
      scope[key] = obj[key];
    } else {
      throw new Error(key + ' variable is already declared.');
    }
  });
}

var o = {
  one: 1,
  two: 2,
  three: 3,
  four: 4
};

destructure(o);

console.log(one); // 1
console.log(two); // 2
console.log(three); // 3
console.log(four); // 4
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
jstice4all
  • 1,878
  • 4
  • 22
  • 33
  • 1
    You're assuming this points to the global object, this is not always the case. When in strict mode for example, this does not point to the global object. – Wazner May 17 '17 at 13:56
  • A "pitfall" is usually when you are trying to achieve `A` but don't realize that what you actually end up with is `Á` (very similar but subtly different). But maybe you actually want to do `Á` and are fully aware of the implications. So in order to show you possible pitfalls we would need to know what you actually want to achieve with this. – Philipp May 17 '17 at 13:57
  • I want to use this function as a helper to destructure an argument of a function that is object with many properties. – jstice4all May 17 '17 at 13:59
  • Do you really want to add all properties of an object to the global scope? Why? Below you are saying that you are using Node.js. I'd argue that one of the main benefits of Node is to be able to compartmentalize code into modules. Adding values to the global scope/object seems like a step backwards from this perspective. If you plan is to add properties of an object to the scope where the function is called from, then that's generally not possible. Function / module scopes are not backed by an object and there is no way to refer to them as objects. – Felix Kling May 17 '17 at 16:10

4 Answers4

3

Are there any pitfalls of declaring variables through this keyword?

Yes: It doesn't really work.


There might be a misunderstanding about how this and scope work.

About scope

You can only declare variables by adding a property to an object is when the environment is backed by an actual object. This is only the case for two situations:

  • Global scope, which is (partially) backed by the global object (window in browsers)
  • The with statement

Examples:

// Global scope
window.foo = 42;
console.log(foo);

// with statement
var obj = {};
with (obj) {
  obj.bar = 21;
  console.log(bar);
 }

Since you mention that you are using Node, I want to emphasize that function scope and module (which are just functions in Node anyway atm) scope are not backed by objects, thus there is no way to dynamically declare variables.

About this

The value of this depends on how a function is called. It could basically refer to any value.

Now, calling a(n unbound) function the "normal way", i.e. as f(), has this arbitrary behavior that this will refer to the global object, e.g. window in browsers. Of course being the global scope, any variable added there is accessible every else, but that's not necessarily a good thing.

So, while your solution may seem work, it really only works coincidentally when you run your code in global scope.


About strict mode

Strict mode changes some of the behaviors that were deemed incorrect or dangerous. Most importantly it changes how this inside normal function calls (f()) behaves. Instead of referring to the global object, it will simply be undefined. Thus if your function was declared in strict mode, your code would actually throw an error.

The with statement is also forbidden in strict mode.

With ES2016, new constructs such as classes and modules are strict by default, so you can see that that's the direction where the language is developing and you should not rely on behavior that doesn't work in strict mode.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
1

This is the programmatic approach to:

this["one"] = 1
this["two"] = 2 
this["three"] = 3
this["four"] = 4

While this theoretically fine, you may run into trouble by relying on this. It would be better to directly specify global, so that you don't run into trouble with .bind() and friends.

function destructure(obj, scope) {
  scope = scope; // Remove the this
  Object.assign(scope, obj);
}
destructure(o, global) // Explicitly declare global scope

As for memory leaks, performance, etc. (which I feel this question is more about), you have to remember that everything that you assign to global never gets Garbage Collected. You should really only add functions to global, and that's only if you really have to.

bren
  • 4,176
  • 3
  • 28
  • 43
1

declares variables in given scope through assigning properties to the scope object

No, that's not how a variable declaration works. Also, the only "scope object" that is available to JS - ignoring the with statement - is the global object (which you happened to use in your proof of concept), and you don't want to mess with that.

Can I use this function in production?

Absolutely not.


If you're sold on the idea, you probably can hack it with eval, but really you just should use real destructuring like everyone else:

var {one, two, three, four} = o;
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

Why not use just Object.assign?

function destructure(obj, scope) {
  scope = scope || this;
  Object.assign(scope, obj);
}
Reski
  • 169
  • 7