Are there any pitfalls of declaring variables through this keyword? - javascript

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

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.

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;

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.

Why not use just Object.assign?
function destructure(obj, scope) {
scope = scope || this;
Object.assign(scope, obj);
}

Related

Is it possible to Detect Closure Programmatically?

I have a function which allows user to pass a function.
function withPredicate(func){
//...
}
Inside my function, I need to detect whether the func that user pass in has closure or not.
It is not enough to get the function name and search it in window scope. User might pass in an anonymous function without closure like:
var func = function(x){return x;};
withPredicate(func);
EDIT:
I think I need to implement a function which takes a function as a argument and return bool.
function hasClosure(func){
//...
}
so several test cases are:
hasClosure(function(x){return x;}); //return false
var something = 30;
var func1 = function(x){return x.age < something;}
hasClosure(func1); //return false
var Closure = function(){
var something = 18;
var itself = function(x){
return x.age < something;
};
return itself;
};
var func2 = new Closure();
hasClosure(func2); //return true
The last one return true because func2 is not top-level function. When I see some free variable inside the function body like something, it may resolve to the variable defined in its closure other than the one defined in window.
Actually, what I need to do now is to do some manipulations based on the func that has been passed to my function. I can use JSLint to get the undeclared variable. But I also need to resolve these variables. It is acceptable that I can only resolve variables in global scope. But I still need a way to make sure that resolving these variables in global scope is correct. So I need to detect closures.
Is it possible to do that programmatically in javascript?
Alright this is really hacky and probably not worth the effort in actually writing unless your linting or something :)
Basically what you're going to have to do to determine if a function is a closure is call func.toString() which will give you the source of the function. You can then parse the function using some sort of parser which determines all the variables of the function func. You also need to determine and track how these variables are defined. In your criteria in op the criteria for it being a closure is having a variable that is defined outside of function scope and outside of window scope (thus closure scope). So if you can find any variables defined outside of these two scopes we've found a closure.
So heres the pseudocode of hasClosure(), have fun implementing.
func hasClosure(func)
source = func.toString(); //eg "function x(a) {return new Array(a)}"
variables = parseJSForVariables(source)//finds a and Array
for variable in variables:
if(variable not in window)
if(variable not defined in function)
return true //we got a closure
return false //not a closure
The correct answer highly depends on what a "closure" means in this context. The function from the question does not use the variables from the outer scope so, roughly, closure is not created for this function. But strictly speaking, closure is created for any function and binds definition context with the function. So whatever you want to detect, it requires a detailed specification.
But I can assume that the closure here means whether the function references variables declared in outer scope (just like https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures specifies). One of the static for analysis libraries can be used for this. For example, JSLint reports used but undeclared variables. Assuming that undeclared variables are just from the upper scope, this indicates that closure is created.

change a custom binding handler so that it is assigned using an IIFE

I have a custom binding handler and want to modify it to IIFE. I have been reading on internet about IIFE but could not able how to change my custom handle into IIFE. So how can I change following binding handler into IIFE
define(['knockout', 'jquery'], function(ko, $) {
ko.bindingHandlers.er = {
init: function(el, va) {
console.log($(el).find('.n').text());
$(el).find('.edit').hide().end().find('.detail').show();
$(el).find('.ebtn').on('click', function() {
$(el).find('.edit, .detail').toggle();
});
$(el).find('.ubtn').on('click', function() {
$(el).find('.edit, .detail').toggle();
});
}
};
});
It's quite unclear what you're asking here :(.
Immediately-Invoked Function Expression (IIFE) is an anonymous function that executes immediately. In your case, if you can't be more specific, it's really hard to guess where do you want to place the iife.
I normally put my whole code into an iife in order to take advantage of the function scope and use it as a closure, thus minimising the global object pollution and it generally looks like this :
(function(global,undefined){
// the code goes here
// global === window
})(this);
In your case, you can do the same :
(function(global,undefined){
define(['knockout','jquery'],function(ko,$){
// ...
});
})(this);
Update :
Here are some explanations for those who need them.
The following pattern is used:
to prevent global variable leaks such as var foo = bar; (after which window.foo === foo)
to prevent the undefined value to get overwritten. Let's say you want to check if something is undefined. you have 2 ways to do it :
typeof foo === 'undefined'
foo === undefined
the second one is shorter but is often not preffered because one can simple overwrite the undefined variable's value : undefined = 13;.
By not proviiding an actual value for the undefined argument in the iife, you're actually resetting the undefined variable to undefined.
to generalize the global object
some say that the access to the global variable is faster than to the window object due to the fact that the js engine first looks into the lower scope
if you're running the code in a different environment than the browser and you have calls to the window object, your code might break because the global object is different from environment to ennvironment (adobe pdfs, node js, rhino ... ). This can be solved by remaping the global object to a variable (in our case global), by reffering it to the this object from the global scope

understanding the javascript global namespace and closures

I'm trying to improve my understanding of the global namespace in javascript and I'm curious about a few things:
is there a "GOD" (i.e. a parent) object that all objects (since all things except primitives are objects) to answer to and if so would that object be "window" ?
why is it bad idea to have vars/functions on a global level?
if it is really a bad idea to have vars/functions in global scope then would closures be the best way to avoid this? example:
function parent(){
var x = 'some value';//this var would be considered global to all children functions but not in the true global namespace
function child1(){
x.someMethod()
}
function child2(){
x*something;
}
function child3(){
x+=something;
child2()
child1()
}
child3()
}
parent()
Is there a god (i.e. a parent) object?
Yes. More technically, it's the global object that all these primitives are members of; it just happens that in the browser, the window object is the global object.
> window.String === String;
true
Why is it bad idea to have vars/functions on a global level?
Because if you're adding lots of 3rd party libraries/ scripts, they all share the same global object, there's the chance of name collisions. This is a real life problem with all the libraries which use $ as an alias (jQuery, Prototype and more).
If it is really a bad idea to have vars/functions in global scope then would closures be the best way to avoid this?
x shouldn't be considered global. It's part of the closure formed by declaring the child functions inside the parent() function. The problem part of your snippet is that parent() is global; what happens if some other code re-declared parent()? This would be better:
(function () {
function parent(){
var x = 'some value';
function child1(){
x.someMethod()
}
function child2(){
x*something;
}
function child3(){
x+=something;
child2()
child1()
}
child3()
}
parent()
}());
The fact x is accessible within the child functions isn't bad; you should have written those functions yourself, so you should be aware of the existence of x. Bear in mind that if you re-declare x within those child functions with var, you won't affect the x in parent().
Yes, in a browser environment the "god object" is window. It's typically called the global object, not god object though ;) In non-browser environments such as nodejs, the global object may use some other name than window.
If you put everything as globals, you risk running into colliding names. There is also the matter of encapsulation - in other words, by putting variables into only the scope where it's needed, your code is usually better off.
Yep, this is pretty much the preferred approach. You can also use IIFE's
As far as I know, I'd say yes, window is the parent object. However, inside an Iframe you have your own window object, distinct from surrounding window which you can access through window.parent
It's a bad idea to have a LOT of global var because of potential name collision and therefore hard to detect bugs. In general it's safer to design some namespace (see
the $ from jQuery, etc) and modularize code.
Be careful, parent is a potential existing field of window. This taken appart, function are object so the same observation than in 2) apply here.
If you NEED to put variables in the global namespace, and you likely will at some point, create a single object variable and add your other variables to it as properties or methods. Give the object a name that is not likely to be used by anyone else (admittedly, this is where collision problems arise, but that can be mitigated by careful, standardized naming).
e.g. Instead of:
var thing1 = 'table';
var anotherthing = 'chair';
var mypet = 'dog';
var count = 4;
var show_something: function( _txt ) { return _txt.trim(); };
Do this:
var cmjaimet_obj = {
thing1: 'table',
anotherthing: 'chair',
mypet: 'dog',
count: 4,
show_something: function( _txt ) { return _txt.trim(); }
};
Then later call them as properties:
e.g. Instead of:
count += 2;
anotherthing = 'sofa';
console.log( show_something( 'Thing: ' + anotherthing ) );
Do this:
cmjaimet_obj.count += 2;
cmjaimet_obj.anotherthing = 'sofa';
console.log( cmjaimet_obj.show_something( 'Thing: ' + cmjaimet_obj.anotherthing ) );

node.js: Confusing usage of 'this' in the global scope

I've been toying with node.js lately and I ran into a weird behavior about the usage of this in the global scope of a module.
this is bound to module.exports in the global scope:
console.log(this === exports); // -> true
But this is bound to global in a method scope:
(function() { console.log(this === global); })(); // -> true
This also lead to this confusing behavior:
this.Foo = "Weird";
console.log(Foo); // -> throws undefined
(function() { this.Bar = "Weird"; })();
console.log(Bar); // -> "Weird"
I guess that the solution is to never use this in the global scope and explicitly use extends or global instead, but is there a logic behind all this or is it a bug or limitation in node.js?
The "logic" behind that is, that the value of this always depends on how a function is invoked.
In your case, you have a self-executing anonymous function, there, this always references the global object (non strict mode) or undefined (ES5 strict).
If you want to access the "outer" this value, you could either store a reference before executing that function, like
var outerScope = this;
(function() { outerScope.Bar = "Weird"; })();
console.log(Foo); // -> throws undefined
or re- .bind() the functions scope yourself, like
(function() { this.Bar = "Weird"; }).bind(this)();
In working on a simple CommonJS modules implementation, I had to think about what to do with this in the global scope of the module; it's not addressed by the spec.
I also set it up as the exports object at first, because I thought that would be useful, but later found some code I needed to "modulize" that was using this to get a handle to the global object, so I changed this back to the global object to provide as close of an environment to "normal" as possible for module code.
We can only guess at why node is set up the way it is (or ask the author), but my guess is it was done simply because it seemed like a useful idea, similar to the way you can give the module object an exports property in node and have it reflected in the module's actual exports (this behavior also isn't part of the spec, but doesn't go against it either).
As for the part of your question about this referencing global in functions, as the other answers explain, that's just the way this works; it's not a node-specific behavior, it's a weird javascript behavior.
I don't know if this is the exact intention of Node.js team, but I would be surprised if it was not. Consider this example ran in the dev console of a browser (e.g. chrome):
var x = function(){console.log(this)}
a = {}
a.x = x
a.xx = function(){x()}
a.x()
>> Object
a.xx()
>> DOMWindow
x()
>> DOMWindow
As you can see executing a method without specifying its context sets the context to be the global one. In this case the DOMWindow object.
When you are inside a module your context is the module, but executing a method in it without specifying a context with .call or .apply or obj. will use the global context, global, instead of the local one, module.exports.

What is the scope of a function in Javascript/ECMAScript?

Today I had a discussion with a colleague about nested functions in Javascript:
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
d = 'Bound to global object.'
}
In this example, trials point out that b is not reachable outside the body of a, much like c is. However, d is - after executing a(). Looking for the exact definition of this behaviour in the ECMAScript v.3 standard , I didn't find the exact wording I was looking for; what Sec.13 p.71 does not say, is which object the function object created by the function declaration statement is to be bound to. Am I missing something?
This is static scoping. Statements within a function are scoped within that function.
Javascript has a quirky behavior, however, which is that without the var keyword, you've implied a global variable. That's what you're seeing in your test. Your "d" variable is available because it is an implied global, despite being written within the body of a function.
Also, to answer the second part of your question: A function exists in whatever scope it is declared, just like a variable.
Sidenote:
You probably don't want global variables, especially not implied ones. It's recommended that you always use the var keyword, to prevent confusion and to keep everything clean.
Sidenote:
The ECMA Standard isn't probably the most helpful place to find answers about Javascript, although it certainly isn't a bad resource. Remember that javascript in your browser is just an implementation of that standard, so the standards document will be giving you the rules that were (mostly) followed by the implementors when the javascript engine was being built. It can't offer specific information about the implementations you care about, namely the major browsers. There are a couple of books in particular which will give you very direct information about how the javascript implementations in the major browsers behave. To illustrate the difference, I'll include excerpts below from both the ECMAScript specification, and a book on Javascript. I think you'll agree that the book gives a more direct answer.
Here's from the ECMAScript Language Specification:
10.2 Entering An Execution Context
Every function and constructor call
enters a new execution context, even
if a function is calling itself
recursively. Every return exits an
execution context. A thrown exception,
if not caught, may also exit one or
more execution contexts.
When control
enters an execution context, the scope
chain is created and initialised,
variable instantiation is performed,
and the this value is determined.
The
initialisation of the scope chain,
variable instantiation, and the
determination of the this value depend
on the type of code being entered.
Here's from O'Reilly's Javascript: The Definitive Guide (5th Edition):
8.8.1 Lexical Scoping
Functions in JavaScript are lexically
rather than dynamically scoped. This
means that they run in the scope in
which they are defined, not the scope
from which they are executed. When a
function is defined, the current scope
chain is saved and becomes part of
the internal state of the function.
...
Highly recommended for covering these kinds of questions is Douglas Crockford's book:
JavaScript, The Good Parts http://oreilly.com/catalog/covers/9780596517748_cat.gif
Javascript, The Good Parts, also from O'Reilly.
As I understand it, these are equivalent as far as scoping is concerned:
function a() { ... }
and
var a = function() { ... }
It seems important to note that while d is being created as a "global", it is in reality being created as a property of the window object. This means that you could inadvertently be overwriting something that already exists on the window object or your variable might actually fail to be created at all. So:
function a() {
d = 'Hello World';
}
alert(window.d); // shows 'Hello World'
But you cannot do:
function a() {
document = 'something';
}
because you cannot overwrite the window.document object.
For all practical purposes you can imaging that all of your code is running in a giant with(window) block.
Javascript has two scopes. Global, and functional. If you declare a variable inside a function using the "var" keyword, it will be local to that function, and any inner functions. If you declare a variable outside of a function, it has global scope.
Finally, if you omit the var keyword when first declaring a variable, javascript assumes you wanted a global variable, no matter where you declare it.
So, you're calling function a, and function a is declaring a global variable d.
...
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
d = 'Bound to global object.'
}
without being preceded by var, d is global. Do this to made d private:
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
var d = 'Bound to local object.'
}

Categories