Given the following JavaScript:
var someFunction = function(id) {
//do some stuff
var modifyId = function(id) {
//do some stuff
outer.id = id; //is there any way to modify the id variable in the outer scope from here?
}
}
How do you modify the id passed into the outer function scope from within the inner function scope?
Unfortunately you can't. By naming the parameter in the nested function id, you've shadowed the parameter in the outer function. Javascript contains no facility for accessing the shadowed name. The only option is to choose a different name for one of the variables.
No, there isn't. From within a function, there's no way (something weird in Mozilla's code or ES5 aside) to refer to the scope as a context in any explicit way, and there's no way to climb up the lexical scope chain in any direct way.
Good question though.
var someFunction = function(id) {
//do some stuff
var oid = id;
var modifyId = function(id) {
//do some stuff
// you can access the outer id via the oid variable
}
}
But, yes, you should just rename one of the formal parameters.
Why can't you just rename one of the variables?
Related
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.
In javascript they are using like:
var self=this;
var jquery_element= $(html_element);
self.jquery_element=jquery_elemnet
Why do we use these in javascript. I got this code from OpenStack horizon
var self=this; is useful for when you have nested functions and this can become ambiguous (in case you dont know this is a javascript keyword). self can be used to still change the this that now reffers to the this from the inner function.
var jquery_element= $(html_element); just provides a easy way to reference the jQuery element without having to constantly recreate it (also provides performance benefit for instance explained here).
self.jquery_element = jquery_element appears to be specific to that code and I'm not quite sure what it does.
It is for visibility in other scope, for using this from one scope, within other scope. Edit.
var parentFunction = function(){
this.msg = "hello world";
var parentScopeSelf = this;
var innerFunction = function(){
var innerFunctionScopeSelf = this;
console.log(this.msg);// undefined (because this now is innerFunction scope, and does not have property msg)
console.log(innerFunctionScopeSelf.msg);// undefined (because innerFunctionScopeSelf is "this" from innerFunction scope, and does not have property msg)
console.log(parentScopeSelf.msg);// hello world (because parentScopeSelf is "this" from parentFunction scope)
}
}
To answer your direct question, this is a javascript keyword, and its value will change depending on its location. By writing its value to a regular variable like self, you are preserving the value wherever self is in scope, even if this itself has changed.
Assigning this to another variable is useful when you have nested functions. For instance:
jQuery(function($) {
$('#myInput').on('keyup', function() {
var $this = $(this); // assign the jQuery's element to $this
$('div.errors').each(function() {
console.log($(this)); // outputs jQuery's object div.errors
console.log($this); // the input is still available in the nested function
});
});
});
As a recommendation, if a variable stores a jQuery element, please prepend it with $. Therefore, it should be
var $jquery_element = $(html_element);
var jquery_element= $(html_element);
is to make the html element be a jquery object that can be use with all the method of jquery.
html_element.fadeOut(); <-- will not work
$(html_element).fadeOut(); <-- will work
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');
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 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).