I am trying to setup a feature as follows.
function Class() {
}
Class.prototype.func = function(f) {
var hello = "hello";
setTimeout(f, 1000);
};
new Class().func(function() {
alert(hello);
});
I want the f() function to be able to access the hello variable. The problem is that f() is not running in the context of the func() function.
I have tried using var hello = "hello"; and this.hello = "hello"; but neither work.
How can f() access hello?
Pass it as a parameter
function Class(){
}
Class.prototype.func=function(f){
var hello="hello";
setTimeout(function(){
f(hello)
},1000);
};
new Class().func(function(hello){
alert(hello);
});
Given the structure of the code you've got, there's no way for any "f" passed into "func" to access "hello".
You could however, do this:
Class.prototype.func=function(f){
this.hello="hello";
setTimeout(f.bind(this),1000);
};
new Class().func(function(){
alert(this.hello);
});
JavaScript scoping is based on the lexical relationship between functions (declaring contexts). A variable declared with var is available to the function in which it's declared, and to all functions declared/instantiated within that function. In your case, the anonymous function is not declared inside "func", so no local variable of "func" can ever be visible to it. There's no way to dynamically expose the local scope from inside "func" either. (I generally forget about ignore eval() when answering questions like this, but here I don't think even eval() could work around the situation.)
It can't. The variable simply does not exist in the scope in which the function is defined.
You would need to expose it to a wider scope (e.g. by making it a property of the instance of the Class object or a global).
Related
What is the difference between these two?
I import both in browserify and they seem to give the same result.
Is there any difference between them and how they work?
var App = (function () {
var Foo = function (name) {
this.name = name;
};
Foo.prototype.logout = function () {
console.log();
}
return Foo;
})();
module.exports = App;
VS
var Foo = function (name) {
this.name = name;
};
Foo.prototype.logout = function () {
console.log();
}
module.exports = Foo;
In this particular case, the only difference is that in the first code sample you end up with a variable named "App", and in the second you end up with one named "Foo". Other than that effect on the namespace, the two do the same thing.
More generally, code that looks like this:
var x = function() {
// lots of stuff
return something;
}();
allows for "lots of stuff" to be done in a context that's isolated from the surrounding context. That means that functions and variables defined inside that anonymous function won't "leak out" into the surrounding context unless that's an explicit goal of the return statement (or other code that otherwise affects some outer context somehow, most typically by direct modifications to window or something like the jQuery prototype).
In your example, again, the "lots of stuff" in the second example didn't involve altering any namespace other than that function prototype, which the first code does too.
Yes, there is difference between these two. First example keeps you safe from polluting your global scope with Foo variable, since it's wrapped in IFEE(Immediately Invoked Function Expressions) and assigned to variable App. Since Foo is inside IFEE it belongs to IFEE's scope.
Foo variable from second example is in global scope and if you import this file in some other code Foo would override variable from that file if there also exist variable with that name. So to be sure that this wouldn't happen it's better to wrap imported code into IFEE.
Also, accessing variable Foo is different, in first example you would access it with App.Foo (since it's namespaced under App) and in second you access it with Foo.
Normally, to create a closure, you create it inside another function, and it gets the scope of its parent:
var parent = function(){
var a = "works!";
var subfunction(){
console.log(a); // "works!"
}
subfunction();
}
I'm trying to figure out a way to emulate this closure behavior with a function that is defined outside of the parent function. I know this is possible using parameters:
var parent = function(){
var a = "hello";
subfunction(a);
}
var subfunction(a){
console.log(a); // works, but because it's a param
}
I'm trying to figure out if there's a way to do it without having to explicitly set all parameters. I was initially thinking I'd be able to pass the functions local scope object as a parameter
var parent = function(){
var a = "hello";
subfunction(localScope);
}
var subfunction(localScope){
console.log(localScope.a); // not going to work this way
}
... but I've since discovered that it's impossible to get a reference to a function's scope. Is there some other way to emulate a closure outside of the actual scope of a function?
No, closures in JS are always lexical (i.e. referring to their parent scope).
If you want to create a closure with an explicitly set environment, you may of course use a helper function for that:
function unrelated() {
var closure = makeClosure("hello");
closure();
}
unrelated();
function makeClosure(a) {
return function() { // closes only over `a` and nothing else
console.log(a);
}
}
That's as close a you will get to an "external closure". Notice you can only pass values to makeClosure, not references to local variables. Of course you could make objects and pass the reference to them around, and with with (not recommended!) you could even make them look like variables.
This question really consists of two:
1 - Do functions create their own $scopes in javasript?
e.g.$scope.foo = function() {
$scope.bar = "Bar";
}
I ask this because in one such test that I'm trying to run I check to determine the existence of a variable on the scope, run a function and then recheck:
iit('getPatientFirstName should attach patientName to the scope', function() {
// Passes
expect(scope.patientName).toBeUndefined();
spyOn(scope,'getPatientFirstName').andCallThrough();
scope.getPatientFirstName(detailsBody);
// Fails
expect(scope.patientName)not.toBeUndefined();
});
// In the controller
$scope.getPatientFirstName = function (dataBody) {
$scope.patientName = dataBody.patientFirstName;
};
So this suggests that they may have their own scope? If this is the case can we test this?
2 - Is a valid alternative just to use an object that exists outside the function:
$scope.patientDetails = {
patientName: ''
};
$scope.getPatientFirstName = function (dataBody) {
$scope.patientDetails.patientName = dataBody.patientFirstName;
};
Thanks
EDIT
Considering the two answers has raised another question - is a variable (attribute or object) considered global if its attached to the $scope? It can be accessed in any function in that controller but as far as being called in a completely different controller - yes it can?
Confirm/Deny anyone?
And it appears that assigning the variable to the $scope global is considered valid for the purposes of my test.
Regarding your first questions, no, functions do not create new $scopes by their own (note that we are talking about scopes and not closures, which are two different concepts).
In your example, the $scope.foo function creates a new bar property on the same $scope object where foo is defined. The final $scope object would look something like this:
$scope {
foo: function() {
$scope.bar = "Bar";
},
bar: "Bar"
}
The problem with your test may be related to the missing . before the not.
expect(scope.patientName).not.toBeUndefined();
Is a valid alternative just to use an object that exists outside the
function:
Yes, you can use an object that's defined outside the function.
If the object is on the same $scope object you will have no problems, just make sure it is defined before you run the function, otherwise you will get a $scope.patientDetails is not defined error.
I'll answer the question a little differently than where you are taking it. I hope it helps you to rethink your stategy.
1 - Do functions create their own $scopes in javasript?
They do create an own scope. But the surrounding scope is also available within the scope. So when you write a function within a function, the inner function can use all the variables of the outer function
Example
function foo() {
var a=5;
function bar() {
var b=4;
}
function hello() {
var c=3;
}
}
a is available for all the functions, foo, bar and hello.
b is not available for foo nor for hello.
c is not available for foo nor for bar.
2 - Is a valid alternative just to use an object that exists outside the function:
So, you should try to make an outer function; there you can declare variables that will be strictly contained within that outer function.
Any function you create within this outer function can make use of that outer scope.
Variables that are global should be avoided if possible.
An example: jQuery.
jQuery has 1 variable that is global: var jQuery ( You can also access it by its alias $ ).
The variables that jQuery uses will not be in conflict with any variables you use.
And anything you want from jQuery, you will have to go through $ (or jQuery)
I'm confused by a javascript design pattern I'm reading about:
var class = (function() {
...a bunch of code...
return {
.. some more code..
;
// or, in some cases
return function(constructorArgs) {
};
})();
My question is: What is the return statement doing? Why is it there? I'm confused because no-one wants to mention it or talk about it.
There's two distinct patterns that you're mentioning, I think.
Anonymous Closures
The first is using an anonymous function to wrap a block of code in order to create a closure:
var outer = (function() {
var inner = "now you see me!";
return inner + " now you don't"
})()
The anonymous function creates a new scope for var-defined variables. In effect, this allows you to define variables that are only visible within that particular function.
In the example above, you have access to inner within the function, but it is not defined outside of it.
"Classes"
The second is a common pattern for defining "classes" in JavaScript:
var MyClass = (function() {
function MyClass(arg) {
this.arg = arg
}
return MyClass
})()
By defining the constructor function within a closure, you can be sure that your class is well contained. It also enables you to share class-wide state or private helper methods without polluting the global namespace, or resorting to placing them as properties on your class constructor's prototype.
the code to the right of the = symbol is of this form: (function(){})(); What this does is compile a function - effectively the same as the following:
function temp() {
}
class = temp();
Inside the function in your example, however, there is another function being returned. What this means is that class is now also a function - the class function can then reference all of the variables etc. that are declared in the temp function, due to the closure effect referenced by vtortola.
The idea of this is to allow the inner function to refer to some state that you don't want to have hanging around in your "global" (or semi-global) scope - it doesn't matter where the class method is called, or who by, it will always have access to that data.
Edit: It appears from the code that the purpose of the pattern in this case is to create a "class" type function - so then you'd be able to call it with the following code:
var myInstance = new class();
Though I've a feeling that none of the code will work as I'm reasonably certain that class is a reserved word...
This is called a closure.
var myVar = (function (param1, param2){
//do things
}('myParam1','myParam2')):
The javascript engine will immediatly execute what is between the parenthesis.
And the value of myVar will be what the function function (param1, param2){ ... } returns.
This function will use ('myParam1','myParam2') as arguments.
You can write closure in two different ways :
(function (receivedArgs){
//do things
})(yourArguments);
or
(function (receivedArgs){
//do things
}(yourArguments));
It is a closure. A function is returning an inner function enclosing some variables in the middle.
https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures
Cheers.
I'm trying to learn JS on codeacademy and I can't understand/get past this thing. Can someone please provide an answer and also an explanation of why is it so? Would deeply appreciate.
// This function tries to set foo to be the
// value specified.
function setFoo(val) {
// foo is declared in a function. It is not
// accessible outside of the function.
var foo = val;
}
setFoo(10);
// Now that we are outside the function, foo is
// not defined and the program will crash! Fix this
// by moving the declaration of foo outside of the
// function. Make sure that setFoo will still update
// the value of foo.
alert(foo);
You can see scope as a term meaning what variables you can reach at a specific "level" in the code. In JavaScript, these "levels" are defined by functions. Each function introduces a new level.
For example, take this sample code:
var a;
// you can access a at this level
function function1() {
var b;
// you can access a, b at this level
function function2() {
var c;
// you can access a, b, c at this level
}
}
So in your case, you should declare var foo; outside the function, preferably above it. Then you can set it inside setFoo with foo = val;. foo then refers to the one you declared in the level above setFoo.
foo is accessible both in setFoo and in the alert call that way; compare it with the above sample code (function1 is setFoo, a is foo and the alert call is in the top-most level. function2, b and c are not used in your case.).
// Create globale variable
// (You should not use globale variables!)
var foo;
// set value
function setFoo(val) {
foo = val;
}
setFoo(10);
// show value
alert(foo);
Just declare foo outside any function then it will be global:
var foo = null;
function setFoo(val) {
foo = val;
}
setFoo(10);
alert(foo);
Try it !
When you declare a variable in Javascript it is only visible to code that is in the same function as it is declared, or a function inernal to that function. Because foo is originally declared in the SetFoo function nothing outside of SetFoo is able to see it, so the call to alert fails as foo does not exist in the gloabl scope.
As the comments suggest, moving the declaration of foo out of the function and into the global scope (which you can think of as a catch-all function that contains everything) would allow you to use foo when calling alert.
var foo;
function setFoo(val) {
foo = val;
}
setFoo(10);
alert(foo); // No longer crashes
Every function in Javascript has it's own scope. That means that every variable you define there with the var keyword, will only be available within that function. That means that when you call setFoo(10), you create the variable foo, give it a value of five, after which it is immediately destroyed because it went out of scope.
There are multiple ways to solve this problem. The first would be to remove the var keyword. This would put foo in the global scope, which means that it's available everywhere. However, this is discouraged, you want to keep the global scope as uncluttered as possible, so that if you have javascript code provided by multiple people on the same page, they can't overwrite other people's variables. Another way to do it would be this:
function setFoo(val){
var foo = val;
alertfoo = function(){
alert(foo)
}
}
In this example, the only thing you're putting in the global scope is the alertfoo function, because you want that to be available everywhere. The alertfoo function is defined inside the setFoo function, this means that although foo should have gone out of scope after setfoo has been executed, it is kept in memory, because alertfoo has access to it.
This makes for some nice tricks. For example, let's say you're making a javascript library that will be included on other people's pages, you'll want to create a scope inside of which you can define variables, without polluting the global scope. The most common way to do this, is by declairing a self-executing function. This is a function which is executed immediately after being defined, it looks like this:
(function(){
//set variables you want to be global in your own code
var mainpage = document.getElementById('main');
//define functions you want to make available to other people in a way that puts them in the global scope
setMainElement = function(newmain){mainpage = newmain;}
})();
You can make this even better by making only one object global, and provide your interfae through the methods of that object, this way, you create a namespace with all the functions that your library contains. The next example uses an object literal to do this. In javascript, you can create an object by putting key/value pairs petween curly braces. the key/value pairs are properties of the object. for example:
(function(){
var privatevar = 10,otherprivate=20;
publicInterface = {
'addToPrivate': function(x){privatevar+=x;},
'getPrivate': function(){return private}
};
})();
Original code:
function setFoo(val) {
var foo = val;
}
setFoo(10);
alert(foo); // Crash!
Their advice to fix the crash:
Fix this by moving the declaration of foo outside of the function
I'm guessing you're confused as to what they mean by "outside of the function".
Try this edited code:
var foo = 5; // "var" declares the variable to be in this outer scope
function setFoo(val) {
foo = val; // but we can still access it in this inner scope...
}
setFoo(10);
alert(foo); // Displays a dialog box that says "10"
Variables defined in the function is valid only in the function
function setFoo(val) {
foo = val;
}
In JavaScript, new scopes are only created by functions