In JavaScript, is it possible to specify the global context which will be used if a local variable isn't defined?
Example:
(function foo() {
console.log(bar);
})();
It will actually print window.bar.
Can I somehow change the global context? Something like this:
var myGlobalContext = { bar: "foo" };
(function foo() {
console.log(bar);
}).applyWithGlobal(myGlobalContext);
It should print myGlobalContext.bar.
Or attach this to be the global context?
I hope the example is clear enough.
The closest thing you can do is mask the global variables using a with statement.
var myGlobalContext = {bar: "foo"};
with(myGlobalContext)
{
console.log(bar);
}
This is not the same as changing the global context, because other globals that aren't found in myGlobalContext will still exist.
In general, the with statement is bad, but it sounds like your use case might be one where it makes sense.
You can do it by using .call() and referencing the variable via this.xyz inside the function:
(function foo() {
console.log(this.bar);
}).call(myGlobalContext);
The only other way is by wrapping the function call in another scope:
(function() {
var bar = '123';
(function() {
console.log(bar);
})();
})();
You can do something like this by passing the namespace to the IIFE:
var myNamespace = { bar: "foo" };
(function( ns ) {
console.log( ns.bar );
}( myNamespace ));
Related
Here is an example. I know it doesn't work because bind() just bind the arguments of a function.
global_var = 2
var foo = function(){
console.log(global_var)
}
var bar = foo.bind(null,/* global_var =*/ 3)
setTimeout(bar)
In my case, foo is from a library so it cannot be modified (not understand why it use global scope), that's why I cannot bind a scope "this" to the function.
bar is going to be a callback, and I want to make sure that it can output '3' every time.
You can always extend your global function. Check the below code snippet.
Hope this helps you!
var global = 2;
//your global library variable
var foo = function() {
console.log('inside foo library');
};
//make the global function extended
foo = (function(oldFn) {
function newFoo() {
oldFn();
console.log('inside extended function')
return 3;
}
return newFoo;
})(foo);
//callback variable
var bar = foo;
console.log(bar());
I have a very confusing situation...
(function sayStuff(){
this.word = "hello2";
(function (){
console.log(this.word);
}())
}())
var myObject = {
word: "bar",
func: function() {
(function() {
console.log(this.word);
}());
}
};
myObject.func();
Outputs
hello2
hello2
How is this happening? How can the closure on the 'func' of myObject actually see the variable that is referenced in sayStuff()? I thought IIFE were meant to protect internals from Global scope?
In both cases, this is window, the global default context replacing the one you don't provide when you call the internal function expressions.
If you want to keep the context, don't use IIFE internally or call them with the context :
(function sayStuff(){
this.word = "hello2"; // still this is window, use var if you don't want that
(function() {
console.log(this.word); // window.word
}).call(this); // well, this is window...
}())
var myObject = {
word: "bar",
func: function() {
(function() {
console.log(this.word); // myObject.word
}).call(this);
}
};
myObject.func();
IIFE only hide locally scoped variables (i.e. those created with the var keyword).
All your functions that touch this.word are invoked in the global context (i.e. not as methods of an object, not with the new keyword and not with apply, call or bind), so this is window in each case. You are dealing with global variables.
If you wanted a private variable you would do something more like this:
(function (){
var word = "hello2";
(function (){
console.log(word);
}())
}())
I decided to create a funcB function that I call from funcA. I want all variables from funcA to be available in the funcB so func B can change that variables.
How to modify the code below so it meets my requirements? I doubt passing all variables it the only possible and the best way.
function funcB(){
alert(var1);//how to make it alert 5
alert(var20);//how to make it alert 50
}
function funcA(){
var var1=5;
...
var var20=50;
funcB();
}
var obj = {
one : "A",
two : "B",
fnA : function() {
this.fnB(); // without fnB method result will be displayed as A B, with fnB as C D
console.log(this.one + " " + this.two);
},
fnB : function() {
this.one = "C";
this.two = "D";
}
};
obj.fnA();
this keyword refers to obj object
You can define object with properties and methods inside it. With methods all the variables can be manipulated as you wish, from this example with fnB I'm changing values of properties which are displayed from fnA method
JSFiddle
One way is to drop the var keyword:
function funcB(){
alert(var1);//how to make it alert 5
alert(var20);//how to make it alert 50
}
function funcA(){
var1 = 5;
var20 = 50;
funcB();
}
This will expose them to the global scope so funcB can access them. Notice you can also create the varaibles in the global scope itself, with the var keyword, but both methods will ultimately have the same effect.
Note:
This may not work if there is already a var1 or var20 in the global scope. In such case, it will modify the global value and may result in unwanted errors.
This method is not preferred for official code, and is bad practice Reason
This is not possible as when you declare a variable with the var keyword, they are scoped to the function in which they are declared.
If you avoid the var keyword, they are instead defined as a global variable. This is deemed very bad practice.
I would recommend you read up on javascript coding patterns, particularly the module pattern.
For example:
var myNamespace = (function () {
var foo, bar;
return {
func1: function() {
foo = "baz";
console.log(foo);
},
func2: function (input) {
foo = input;
console.log(foo);
}
};
})();
Usage:
myNamespace.func1();
// "baz"
myNamespace.func2("hello");
// "hello"
This question already has answers here:
JavaScript: Reference a functions local scope as an object
(5 answers)
Is there a Javascript variable that represents local scope? Like global?
(1 answer)
Closed 8 years ago.
I know that variables are properties of other objects. For example:
var myVar = 'something';
is a property of the window object (if it is in the global scope of course).
if I want to find the variable's object, I just use the this variable. But:
function f() {
var myVar2 = 'something';
}
Which object does myVar2 belongs to? (myVar belongs to window object, but what about myVar2?)
I would like to know that, thanks.
It doesn't belong to an object. It belongs to the scope of the function f. You access it by doing myVar within f. You cannot access it outside of f.
If you did
function f() {
this.myVar = 1;
}
now you can do
var myF = new f();
myF.myVar
indeed, this how user defined objects are sometimes defined.
myVar2 belongs to the local scope (of f), and myVar the global scope.
var does some interesting things. var statements are hoisted to the top of their functional scope. The var's functional scope is whatever function it happens to be in.
JavaScript doesn't have block-level scope, which means that:
(function () { //a closure to create new scope
var foo;
foo = 1;
if (condition) {
var bar;
bar = 3;
}
}());
...is equivalent to...
(function () {
var foo,
bar;
foo = 1;
if (condition) {
bar = 3;
}
}());
If the var statement has no parent, it will instead add the variable as a property to the global context, which in web browsers happens to be window.
This is the only time that using var will create a property. If want to create a property of an object, you simply have to set it:
(function () {
var foo;
foo = {};
foo.bar = 'baz'; //this creates the `bar` property on `foo`
}());
JavaScript is a prototypal language with prototypal inheritance. Functions are first-class objects (because JavaScript isn't racist against functions). This means that functions can be used just like any other object.
You can set them:
(function () {
var foo;
//foo is now a function
foo = function () {
alert('Hello World');
};
}());
You can set properties on them:
(function () {
var foo;
foo = function () {
alert('Hello World');
};
foo.bar = 'baz'; //this works just fine
}());
You can even pass them as parameters:
(function () {
var foo,
bar;
foo = function () {
alert('Hello World');
};
bar = function (c) {
c();
};
bar(foo); //guess what this does?
}());
Another cool thing that functions do, is they act as constructors. All functions are inherently constructors, you just need to call them using the new keyword:
(function () {
var foo; //case sensitive
//it doesn't matter whether you use `function Foo`
//or `var Foo = function...`
function Foo() {
alert('Hello World');
}
foo = new Foo();
foo.bar = 'baz';
}());
The important detail in using constructors is that the function's context (this) will be set to the object created by the constructor. This means that you can set properties on the object within the constructor:
(function () {
var foo;
function Foo() {
this.bar = 'baz';
}
foo = new Foo();
alert(foo.bar); //'baz'
}());
Why does self-invocation function inside a function don't get the scope of the outer function in JavaScript?
var prop = "global";
var hash = {
prop: "hash prop",
foo: function(){
console.log(this.prop);
(function bar(){
console.log(this.prop);
})();
}
};
var literal = {
prop: "object"
};
hash.foo();
// hash prop
// global
hash.foo.call(literal);
// object
// global
Looks like altering the scope of the outer function has no effect on the scope of the inner self-invocation function.
PS: The question is not about how to alter the scope of the inner function. But what is the proper explanation in the "Javascript language" perspective? Does all self executing functions have 'global' scope by default? If so, why?
Your problem is the this and what it references:
foo: function(){
console.log(this.prop);
(function bar(){
console.log(this.prop); <--- this does not reference to foo here, but instead it refers to the window object
})();
}
You need to keep a reference to the outer this:
foo: function(){
console.log(this.prop);
var that = this;
(function bar(){
console.log(that.prop); <--- tada!
})();
}
Update
Some explanation. It's all about how JavaScript determines the context when invoking a function.
function Test() {
this.name = "Test";
this.bar = function() { console.log("My name is: "+ this.name);}
}
function Blub() {
this.name = "Blub";
this.foo = function() { console.log("My name is: " + this.name);}
}
var a = new Test();
var b = new Blub();
// this works as expected
a.bar(); // My name is: Test
b.foo(); // My name is: Blub
// let's do something fun
a.foo = b.foo; // make an educated guess what that does...
a.foo() // My name is: Test
Huh? Aren't we referencing the method of Blub? No we're not. We are referencing the unbound function of Blub.
JavaScript binds on . (dots) and based on that it decides waht the value of this should be.
Since you're not calling your anonymous function on an object (therefore no .) it will make this reference to the global object, which is - in case of the browser - the window object.
Another example (one might think this would work):
var str = "Hello World";
var ord = str.charCodeAt; // let's make a little shortcut here.... bad idea
ord(0) // no dot...
Instead of the char codes that are in str we get the ones that are in the global object, of course that's not a string so charCodeAt calls toString on which results in "[object DOMWindow]"
You are not applying any object as the this context when you call the inner function, so it gets this set to window by default. If you wanted to call the closure with the same this as the outer function, you would have to do:
(function bar(){
console.log(this.prop);
}).call(this);
Or:
var that = this;
(function bar(){
console.log(that.prop);
})();