Ever since let came out it allowed me to follow stricter naming conventions.However, lets consider the below scenario, would it be valid or is it hacky to do something like this? I am very well aware that the first has function scope and the other block scope.
var sample = 'sample';
function fooBar() {
let sample = 'This is a sample';
console.log(sample);
}
fooBar();
console.log(sample)
What you are trying to do here is perfectly valid and is called shadowing. As the name suggests - You have shadowed the global scoped variable sample with the function scoped variable sample. And by doing that you have restricted yourself to access the global variable without using some special tricks.
You can still access global variable of the same name inside the function as given below
var sample = 'sample';
function fooBar() {
var sample = 'This is a sample';
console.log(sample); // 'This is a sample'
console.log(window.sample); //Sample
//console.log(this.sample);//Sample. Works only in non strict mode
}
fooBar();
console.log(sample); // 'sample'
Moreover, if someone says never use var then that little too hard a statement to make. var still has its use. You can have a look at this article by Kyle Simpson here
https://davidwalsh.name/for-and-against-let
Hope this be of some help.
Happy Learning :)
Vatsal
It's valid.
And since one declaration is outside the function and the other is inside, you could even declare both with var:
var sample = 'sample';
function fooBar() {
var sample = 'This is a sample';
console.log(sample); // 'This is a sample'
}
fooBar();
console.log(sample); // 'sample'
Related
I have some simple code here that I'm running in Visual Studio Code with Quokka and NodeJS.
var str = "hello"
function printStr(){
console.log(this.str);
}
printStr();
Output:
undefined at this.str quokka.js:6:4
I can run this code in my web browser just fine, and it works just fine, printing out "hello".
"use strict"; is not enabled
Screenshot: https://i.imgur.com/IEQwv5D.png
In a browser this will be interpreted as the window object in this case and the variable str will be defined on the window. There is no window object in Node. It's not clear why you are using this at all here rather than using regular scoping rules. This will work in both the browser and Node:
var str = "hello"
function printStr(){
console.log(str); // will see outside scope
}
printStr();
Better yet, pass the value into the function so it doesn't depend on values defined outside its scope:
var str = "hello"
function printStr(s){
console.log(s);
}
printStr(str);
In Node there is a global object, which has some similarity to the browser's window object so code like this can work in Node, but it would be a fairly non-standard way to do this:
global.str = "hello"
function printStr(){
console.log(this.str)
}
printStr();
Inside a function this normally refers to the window object and the variable str is not defined on window.
You may simple call it like
var str = "hello"
function printStr(){
console.log(str);
}
printStr();
I hope mi answer will be to help. The object 'this' is undefined in node JS for the element window not exist and you aren't working with any object or constructor or class.
For example:
var Animal = function(kind) {
this.name = "NN"
this.kind = kind
};
Animal.prototype.printName = function() {console.log(this.name)};
Animal.prototype.setName = function(name){this.name = name}
var a1 = new Animal("Lion");
var a2 = new Animal("Cat");
a1.setName("Robert");
a2.setName("Alex");
a1.printName();
a2.printName();
Please look at the code when I use the sentence this. if you have a questions, please write me! (Y)
I have a minified javascript file. I can send it through a variety of tools to insert newlines and indentation. What I then want is to fix the variable names. I know that no tool can do this automatically. What I need is a tool that will augment my attempt to do so manually. It needs to be aware of scope rules so that when I rename c to length and d to height and j() to move(), those changes will be made everywhere that the same c and d and j are used, but not in other scopes where different variables and functions with those same names exist.
Is there a tool like this, specifically designed for reversing minification? If there isn't a tool for this specific job, is there a smart IDE that can at least handle renaming variables or methods following scope rules?
I found an in-browser/downloadable node.js library tool that does rename refactoring very well. Esprima handles the following ES6 code (slightly modified from the example) such that when I change the name of any of the global scope hi, only the hi names surrounded by a comment block are changed (I couldn't think of a better way to call out code since markdown doesn't show in code blocks, sorry).
// Array shuffling code from Underscore.js, code modified from base example on http://esprima.org/demo/rename.html
var shuffled;
var /*hi*/ = 'hi'; // initial declaration
function /*hi*/() { // modifies var above
this.shuffle = 'x';
}
_.shuffle = function(obj) {
function hi() {
return 'hello';
}
var shuffled = [], rand;
each(obj, function(value, index, list) {
rand = Math.floor(Math.random() * (index + 1));
shuffled[index] = shuffled[rand];
shuffled[rand] = value;
});
hi(); // calls function defined above, name not changed by change to global scope 'hi'
console.log(hello); // considered to be the same as the let statement below even though this is a syntax error since let doesn't get hoisted like var
return shuffled;
};
let hello = 'hello';
function hiNotInScope() {
var hi = 'something else'; // not in global scope, so change to global hi doesn't change this
console.log(hi); // changed if the hi in this scope is changed
}
// hi (not changed since it's in a comment)
/*hi*/(); // calls global hi function.
It seems to respect scoping rules as long as there are no code errors (for example, a let declaration above a var declaration of the same name that gets hoisted above the let will be considered in-scope, but this is a non-issue since it's a syntax error).
Disclaimer: I'm not sure that I'm using the correct terminology.
Given this code:
var sample = 'Text';
var test = function(sample) {
console.log(sample);
};
test('Text Too');
I am aware that if the function parameter had a different name, the console.log() call would output "Text". Is there a way for the test() function to reference the "parent scope" variable, sample without changing the name of the function parameter? If so, how?
No, there is no way to do this in JavaScript. If you use the same variable name in the inner scope, the outer scope variable becomes completely inaccessible to that inner scope.
Edit: Except, of course, when the outer scope is the global scope. Then you could use window.sample.
#plbsam is right, he shouldn't have deleted his answer.
In your specific case, this inside a function is the context it is called in: docs
var sample = 'Global var';
var test = function(sample) {
console.log("sample: "+sample);
console.log("this.sample: "+this.sample);
};
test('Local var');
EDIT:
as this all depends on the scope the function is called in you can always assign this to a separate var in the global scope to be able to access it anywhere:
// this var can now be accessed inside any function as a reference to the global scope.
global = this;
var sample = 'Global';
var test = function(abc) {
console.log("sample: "+sample);
console.log("this.sample: "+this.sample);
console.log("global.sample: "+global.sample);
};
test('Local');
I know using eval is not at all recommended and I have read this link too. Set Variable inside Eval (JavaScript)
However, this is what I want to do. Lets say we have some code in a textbox. So I have to take that text, and then find out all the global variables, functions and objects in that code.
My idea was to wrap the code in a namespace, eval it and then iterate through the properties of the namespace to get the results. However, even though the eval runs successfully, I can't access the variable defined there. Is there a better solution or some other way to get this working.
http://jsfiddle.net/DbrEF/2/ - This is the Fiddle here.
The "var code" could actually be arbitrary code. I know its unsafe to do it but I need it for a different context.
Thanks
In 2015, creating a Function object is your best bet here, rather than using eval:
new Function('arg1', 'arg2', 'return arg1 + arg2')(3,4) // returns 7
You might have better luck using a Javascript parser, like the one used by JSHint/JSLint
here's a demo on safely using eval using "use strict"
window.onload = function(){
'use strict';
//use strict forces to run code in "strict mode"
//use strict prevents eval from
//contaminating the immediate scope
//let's test with "foo"
var foo = 'lol';
//now code has "foo" but using "use strict"
//makes code in eval stay in eval
//note that at the last of the code, foo is "returned"
var code = 'var foo = {name: "Spock",greeting: function() {return "Hello " + foo.name;}}; foo';
//store eval'ed code in evalO
var evalstore = eval(code);
console.log(evalstore); //code in eval stays in here, which is "inner foo"
console.log(foo); //"outer foo" is unharmed and daisy fresh
};
so whatever code you have, contain it in a function which will serve as your namespace. then have that function returned to the outside world stored as a variable. this demo shows how it can be constructed, however, works only if code is in object literal notation.
window.onload = function() {
'use strict';
var ns = 'lol';
//code must be an object literal
var code = '{name: "Spock",greeting: function(){return "Hello " + foo.name;}}';
//store in a constructor to be returned
var constructorString = 'var ns = function(){return ' + code + '}; ns';
var evalNs = eval(constructorString); //type function/constructor
var evalObj = new evalNs() //object instance
console.log(evalNs); //constructor
console.log(evalObj); //the namespaced object
console.log(ns); //outer "ns" preserved
};
Probably not what exactly OP was looking for but another option is to use outside variables to store values generated inside eval, as in:
var value;
var code = 'var foo = 42';
code = code.replace('var foo', 'value');
eval(code);
value // returns 42;
I am now in the process of removing most globals from my code by enclosing everything in a function, turning the globals into "pseudo globals," that are all accessible from anywhere inside that function block.
(function(){
var g = 1;
var func f1 = function () { alert (g); }
var func f2= function () { f1(); }
})();
(technically this is only for my "release version", where I append all my files together into a single file and surround them with the above....my dev version still has typically one global per js file)
This all works great except for one thing...there is one important place where I need to access some of these "globals" by string name. Previously, I could have done this:
var name = "g";
alert (window[name]);
and it did the same as
alert(g);
Now -- from inside the block -- I would like to do the same, on my pseudo-globals. But I can't, since they are no longer members of any parent object ("window"), even though are in scope.
Any way to access them by string?
Thanks...
Basically no, as answered indirectly by this question: Javascript equivalent of Python's locals()?
Your only real option would be to use eval, which is usually not a good or even safe idea, as described in this question: Why is using the JavaScript eval function a bad idea?
If the string name of those variables really and truly is defined in a safe way (e.g. not through user-input or anything), then I would recommend just using eval. Just be sure to think really long and hard about this and whether there is not perhaps a better way to do this.
You can name the function you are using to wrap the entire code.
Then set the "global" variable as a member of that function (remember functions are objects in JavaScript).
Then, you can access the variable exactly as you did before....just use the name of the function instead of "window".
It would look something like this:
var myApp = new (function myApp(){
this.g = "world";
//in the same scope
alert ( "Hello " + this["g"]);
})();
//outside
alert ( "Hello " + myApp["g"]);
if you want to access something in a global scope, you have to put something out there. in your case it's probably an object which references your closed off function.
var obj1 = new (function(){
var g = 1;
var func f1 = function () { alert (g); }
var func f2= function () { f1(); }
})();
you can add a method or property as a getter for g. if the value of g isn't constant you might do like
this.getG = function() { return g; };
you can work from there to access items by name, like
alert( obj1["getG"]() );
alert( window["obj1"]["getG"]() );