Is there a difference between
function test(){
var myVar;
}
and
function test(){
this.myVar;
}
The value of this is determined by how function is called whereas var VARIABLE_NAME will create a variable in the local-scope of the function.
In second example, you are creating Object-Constructor using which you can create many instances of the test object using new operator
function test(name) {
this.name = name;
}
console.log(new test('Abc'));
console.log(new test('Xyz'));
There are two scopes in javascript , local or function scope and global scope .
In your case this is global and var is local scope/function scope .
If you use this inside IIFE (immediate invoking function expression)and 'use strict' its not global
The most difference is that your first code works like a private property (local scope) and the second is like a public property (global scope).
Examples:
var test = function(){
this.myVar = "test var";
}
var test2 = function() {
var myVar = "test2 var";
}
alert((new test()).myVar);
alert((new test2()).myVar);
Related
We are given a code snippet in run time along with a name of a variable used in code. We want to evaluate the given code and log the value of the variable.
Example:
suppose our code is var foo = "Blah"; and the name of the var is foo.
eval('var foo = "Blah"; let varName = "foo"; console.log(this[varName]);');
yields Blah.
yet
new Function('var foo = "Blah"; let varName = "foo"; console.log(this[varName]);')();
yields undefined.
Is there a way to make get this to work with new Function?
With new Function, you're creating a new function. The code that is executed looks something like:
function someFunction() {
var foo = "Blah"; let varName = "foo"; console.log(this); console.log(this[varName]);
}
someFunction();
There, foo is in local scope of the someFunction. It's not global, so variables declared with var inside the function don't get put onto the global object.
In contrast, eval runs on the top level. Your eval code that is executed looks something like:
var foo = "Blah"; let varName = "foo"; console.log(this[varName]);
which is all on the top level, so the foo variable that was declared gets put onto the global object, the this.
Substitute the variable name into the function definition directly, rather than using this.
let varName = 'foo';
new Function(`var ${varName} = "Blah"; console.log(${varName});`)();
Everything here is about Scope. Global Scope and Block Scope.
Global Scope
Variables declared Globally (outside any function) have Global Scope.
var bikeName = "Honda";
// code here can use bikeName
function myFunction() {
// code here can also use bikeName
}
and
var greeter = "hey hi";
function newFunction() {
var hello = "hello"; //Variables declared Locally (inside a function) have Function Scope.
}
console.log(hello); // error: hello is not defined
Here, greeter is globally scoped because it exists outside a function while hello is function scoped. So we cannot access the variable hello outside of a function.
Block Scope
A block is a chunk of code bounded by {}. A block lives in curly braces.
let times = 4;
if (times > 3) {
let hello = "say Hello instead";
console.log(hello);// "say Hello instead"
}
console.log(hello) // hello is not defined
You should read about them. Things will get clear
Hence in your case:
new Function('var foo = "Blah"; let varName = "foo"; console.log(this[varName]);')();
Everything inside function has function scope and will not be available global!
From the MDN description of Function:
Note: Functions created with the Function constructor do not create
closures to their creation contexts; they always are created in the
global scope. When running them, they will only be able to access
their own local variables and global ones, not the ones from the scope
in which the Function constructor was called. This is different from
using eval with code for a function expression.
I understand,
var y = 10;
var tester;
function test(){
var x = 5;
tester = new Function("a", "b", "alert(y);");
tester(5, 10);
}
test(); // alerts 10
Replacing the tester = new Function("a", "b", "alert(y);"); with tester = new Function("a", "b", "alert(x);");, I will get
// ReferenceError: x is not defined
But couldn't understand the author's line-
...they always are created in the global scope.
I mean how is the new Function("a", "b", "alert(y);"); nested within the test fn is in global scope?
In fact, accessing it from outside the test fn will simply result in
Uncought TypeError:tester is not a function
Please elucidate.
In your example, "created in the global scope" means that tester will not have closure over x from test:
function test(){
var x = 5;
tester = new Function("a", "b", "alert(x);"); // this will not show x
tester(5, 10);
}
When you new up a Function, it does not automatically capture the current scope like declaring one would. If you were to simply declare and return a function, it will have closure:
function test(){
var x = 5;
tester = function (a, b) {
alert(x); // this will show x
};
tester(5, 10);
}
This is the trade-off you make for having dynamically compiled functions. You can have closure if you write the function in ahead of time or you can have a dynamic body but lose closure over the surrounding scope(s).
This caveat doesn't usually matter, but consider the (slightly contrived) case where you build a function body as a string, then pass it to a function constructor to actually be evaluated:
function addOne(x) {
return compile("return " + x + " + 1");
}
function addTwo(x) {
return compile("return " + x + " + 2");
}
function compile(str) {
return new Function(str);
}
Because the function is instantiated by compile, any closure would grab str rather than x. Since compile does not close over any other function, things get a bit weird and the function returned by compile will always hold a closure-reference to str (which could be awful for garbage collection).
Instead, to simplify all of this, the spec just makes a blanket rule that new Function does not have any closure.
You have to create an object to expose via return inside the test() function for it to be global. In other words, add var pub = {} and name your internal functions as properties and/or methods of pub (for example pub.tester = new func) then just before closing test() say return pub. So, that way it will be publically available (as test.tester). It's Called the Revealing Module Pattern.
What it means is that inside the function you can only refer to global variables, as you've found. However, the reference to the function itself is still in the local scope where it was created.
I'm confused as to where the confusion is.
It says that the function will be in global scope...and therefore will only have access to its own scope and the global scope, not variables local to the scope in which it was created.
You tested it and it has access to its own scope and the global scope, not variables local to the scope in which it was created.
So where's the confusion?
Is it in your assigning of the function to the variable testing? testing is just a local variable with a reference to the function...that has nothing to do with the scope of the creation of the function.
Scope is lexical, and has to do with where the function is created, not what random variables a function reference happens to be assigned to at runtime. And the documentation is telling you that when you make a function this way it acts as if it was created in the global scope...so it's acting completely as expected.
Here's an illustration:
This:
var y = 10;
var tester;
function test()
{
var x = 5;
// 10 and errors as not defined
tester = new Function("console.log(y); console.log(x);");
}
Is similar to this:
var y = 10;
var tester;
function test()
{
var x = 5;
// also 10 and errors as not defined
tester = something;
}
function something()
{
console.log(y);
console.log(x);
}
NOT
var y = 10;
var tester;
function test()
{
var x = 5;
// 10 and 5...since x is local to the function creation
tester = function()
{
console.log(y);
console.log(x);
}
}
Here I'm trying to use a variable in function New(), the variable was created in the function Test().
I'm still a bit confuse about how to use global variable.
function New(){
Test();
//this show nothing
alert(myName);
}
function Test() {
myName = "John";
}
New();
Even when I do "var myName;" outsise of these functions, it doesn't work.
Still searching
Check this fiddle
things to change :
1) use function New(){} instead of function New{}
2) return myName from test function and store it in new variable in New function
function New(){
var myName= Test();
//this show nothing
alert(myName);
}
function Test() {
var myName = "John";
return myName
}
New();
update : yeah u can also define myName as global variable and use it
When you want to declare a variable for use, use the var keyword. When you do this, the location of where you do it determines the "scope" of the variable. If you want to use the variable in two functions, you can simply declare the variable outside of both:
var myVariable = "Something";
function1(){
myVariable = "something else";
}
function2(){
myVariable = "something else again";
}
Another way to share data is to pass that data as arguments into a function:
function1(){
var myVariable = "Something";
function2(myVariable);
}
function2(someName){
alert(someName); // "Something"
}
In your case, you didn't use the "var" keyword to declare your variable, so it became global, but you have a typo in your code, so it didn't run.
Its just a small type error. Just add braces after New
var myName; // have myName global ie, outside all functions
function New(){ // needs the braces() for New to be a function
Test();
alert(myName);
}
function Test() {
myName = "John";
}
New();
Declare myName globally, then define myName in the return of Test() function. When declaring a function, always use keyword "function", "()", and "{}" no matter what.
var myName;
function New() {
alert(Test());
}
function Test() {
myName = "John";
return myName;
}
New(Test);
Global variable is something whose scope is for a particular class and not restricted to a function.
You can create variable myName inside class but outside function and use it anywhere within class.
var myName="";
function New{
Test();
//this show nothing
alert(myName);
}
function Test() {
myName = "John";
}
New();
I have this....
function MyFunction() {
var myVar = "I think I am encapsulated";
this.getMyVar = function() {
return myVar;
}
}
var myProperty = new MyFunction();
console.log(myProperty.getMyVar());
myProperty.myVar = "you're not encapsulated";
console.log(myProperty.getMyVar());
It outputs: "I think I am encapsulated twice". Why? I did not think this was a closure...
The closure is around the "getMyVar" function. The variable "myVar" inside the constructor is a local variable, and not visible outside the function except as the return value from "getMyVar".
Setting a "myVar" property on the object does just that, but the "getMyVar" function is not returning a property of an object; it's returning the value of the local variable in the closure.
Yes, it is.
When you define a function inside of another function, the inner function has access to all of the outer function's local variables...
In your case, getMyVar has access to myVar - through the closure.
var myVar = "I think I am encapsulated";
this.getMyVar = function() {
return myVar;
}
This is a closure, and the myVar variable from the time the function was created will be returned. Notice that's it a local variable, so there's no other way to access it after this function exits.
var myVar = "I think I am encapsulated";
Notice that this is not this.myVar (the variable you're setting later with myProperty.myVar).
Probably what you're trying to do is:
function MyFunction() {
this.myVar = "I think I am encapsulated";
this.getMyVar = function() {
return this.myVar;
}
}
What is the difference between declaring a variable with this or var ?
var foo = 'bar'
or
this.foo = 'bar'
When do you use this and when var?
edit: is there a simple question i can ask my self when deciding if i want to use var or this
If it is global code (the code is not part of any function), then you are creating a property on the global object with the two snippets, since this in global code points to the global object.
The difference in this case is that when the var statement is used, that property cannot be deleted, for example:
var foo = 'bar';
delete foo; // false
typeof foo; // "string"
this.bar = 'baz';
delete bar; // true
typeof bar; "undefined"
(Note: The above snippet will behave differently in the Firebug console, since it runs code with eval, and the code executed in the Eval Code execution context permits the deletion of identifiers created with var, try it here)
If the code is part of a function you should know that the this keyword has nothing to do with the function scope, is a reserved word that is set implicitly, depending how a function is called, for example:
1 - When a function is called as a method (the function is invoked as member of an object):
obj.method(); // 'this' inside method will refer to obj
2 - A normal function call:
myFunction(); // 'this' inside the function will refer to the Global object
// or
(function () {})();
3 - When the new operator is used:
var obj = new Constructor(); // 'this' will refer to a newly created object.
And you can even set the this value explicitly, using the call and apply methods, for example:
function test () {
alert(this);
}
test.call("hello!"); //alerts hello!
You should know also that JavaScript has function scope only, and variables declared with the var statement will be reachable only within the same function or any inner functions defined below.
Edit: Looking the code you posted to the #David's answer, let me comment:
var test1 = 'test'; // two globals, with the difference I talk
this.test2 = 'test'; // about in the beginning of this answer
//...
function test4(){
var test5 = 'test in function with var'; // <-- test5 is locally scoped!!!
this.test6 = 'test in function with this'; // global property, see below
}
test4(); // <--- test4 will be called with `this` pointing to the global object
// see #2 above, a call to an identifier that is not an property of an
// object causes it
alert(typeof test5); // "undefined" since it's a local variable of `test4`
alert(test6); // "test in function with this"
You can't access the test5 variable outside the function because is locally scoped, and it exists only withing the scope of that function.
Edit: In response to your comment
For declaring variables I encourage you to always use var, it's what is made for.
The concept of the this value, will get useful when you start working with constructor functions, objects and methods.
If you use var, the variable is scoped to the current function.
If you use this, then you are assigning a value to a property on whatever this is (which is either the object the method is being called on or (if the new keyword has been used) the object being created.
You use var when you want to define a simple local variable as you would in a typical function:-
function doAdd(a, b)
{
var c = a + b;
return c;
}
var result = doAdd(a, b);
alert(result);
However this has special meaning when call is used on a function.
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
doAdd.call(o, a, b);
alert(o.c);
You note the first parameter when using call on doAdd is the object created before. Inside that execution of doAdd this will refer to that object. Hence it creates a c property on the object.
Typically though a function is assigned to a property of an object like this:-
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
o.doAdd = doAdd;
Now the function can be execute using the . notation:-
o.doAdd(a, b);
alert(o.c);
Effectively o.doAdd(a, b) is o.doAdd.call(o, a, b)
var foo = 'bar'
This will scope the foo variable to the function wrapping it, or the global scope.
this.foo = 'bar'
This will scope the foo variable to the this object, it exactly like doing this:
window.foo = 'bar';
or
someObj.foo = 'bar';
The second part of your question seems to be what is the this object, and that is something that is determined by what context the function is running in. You can change what this is by using the apply method that all functions have. You can also make the default of the this variable an object other than the global object, by:
someObj.foo = function(){
// 'this' is 'someObj'
};
or
function someObj(x){
this.x=x;
}
someObj.prototype.getX = function(){
return this.x;
}
var myX = (new someObj(1)).getX(); // myX == 1
In a constructor, you can use var to simulate private members and this to simulate public members:
function Obj() {
this.pub = 'public';
var priv = 'private';
}
var o = new Obj();
o.pub; // 'public'
o.priv; // error
Example for this and var explained below:
function Car() {
this.speed = 0;
var speedUp = function() {
var speed = 10; // default
this.speed = this.speed + speed; // see how this and var are used
};
speedUp();
}
var foo = 'bar'; // 'var can be only used inside a function
and
this.foo = 'bar' // 'this' can be used globally inside an object