I was expecting the obj to be instanceof F1 ('this' in 'this.prop' refers to F1 object in the code snippet below, similarly I thought 'this' in 'return this' of C1 refers to F1 which is not the case. It refers to Global Window object), but in actuality it is an instanceof Window. Why is that ? could you please explain ?
function F1() {
this.prop = 5;
function C1() {
return this;
}
return C1();
}
var obj = new F1();
if you are just creating an instance of F1, then just do this:
function F1() {
this.prop = 5;
}
var obj = new F1();
you don't need to return anything.
the this inside C1 is not the same as this outside it. if you want to preserve this of the outside so that C1 can use it, store it into another variable
function F1() {
//preserve "this" from outside
var that = this;
this.prop = 5;
function C1() {
return that; //"that" is "this" of the outside
}
}
Related
When I use var keyword to declare any variable it gets declared inside the enclosing scope. However in the code below, I have declared function c (inside an object method a.b) with var keyword and still this inside the function c is bound to the global object window. Why is this?
var a = {
b: function () {
var c = function () {
return this;
};
return c();
}
};
document.write(a.b()); //prints: [object Window]
The value of this is determined by context, not scope.
When you call a function without any context (context.func()) as you do there (c()), the default context is the default object (which is window in browsers) unless you are in strict mode (in which case it is undefined instead).
(There are exceptions to this rule, such as apply, call, bind, and new but none of them apply here).
Many people get confused by this. The value this depends on one of 4 methods of invocation.
However, functional invocation and method-invocation cause most of the confusion.
If a function is a member of an object, this is the object itself.
obj.someFunction(); //method invocation
If a function is called without context this is the global object (in 'strict mode' this is undefined.)
someFunction(); //functional invocation
The confusion occurs when a function is called within an object, but not as a member of the object as in anObject.testWithHelper(..);
var testForThis = function(isThis, message) {
//this can be confusing
if(this === isThis)
console.log("this is " + message);
else
console.log("this is NOT " + message);
};
//functional invocation
testForThis(this, "global"); //this is global
var anObject = {
test: testForThis, //I am a method
testWithHelper: function(isThis, message) {
//functional invocation
testForThis(isThis, message + " from helper");
}
};
//method invocation
anObject.test(anObject, "anObject"); //this is anObject
//method invocation followed by functional invocation
anObject.testWithHelper(anObject, "an object"); //this is NOT anObject from helper
Here is my JSFIDDLE
If you would like c to return a, you can use closure:
var a = {
b: function () {
var that = this;
var c = function () {
return that;
};
return c();
}
};
Or avoid this all together:
var getNewA = function() {
var newA = {};
newA.b = function() {
var c = function() {
return newA;
};
return c();
};
return newA;
};
var newA = getNewA();
I have a habit of setting all my variables to its parent scope, instead of calling them implicitly:
function outer() {
var x, y;
function inner() {
var x = this.x;
x = ...// doing stuff here
y = ....// implicit calling parent variable
}
}
so that if I mistype my variable, it won't go to global space. But it seems like declare variable with this within private function will return me undefined:
function f() {
var x = [0];
function f1() {
console.log('f1:', this.x, x);
f2();
}
function f2() {
console.log('f2:', this.x, x);
}
return { x:x , f1:f1 };
}
var foo = f();
foo.f1();
//output
f1: [0] [0]
f2: undefined [0]
If I understand it correctly, it shouldn't happen, as both f1 and f2 should have access to its outer scope by using this. Is there any concept I am missing here? Or is it something I just have to live with for now?
Update: To clarify, my main concern is why there is the difference between f1 and f2. I prefer to keep f2 hidden because it will do some internal works, and other developers should not use it when they declare something from f().
Also try this:
function f() {
var x = [0];
function f1() {
console.log('f1:', this.x, x);
f2.call(this);
}
function f2() {
console.log('f2:', this.x, x);
}
return { x:x , f1:f1 };
}
var foo = f();
foo.f1();
This way the context of f2 will be properly set.
In your code this in f2 refers to the window object, because f2 wasn't declared as a method. f1 was declared as a method of the returned object when writing { x:x , f1:f1 }. In f2 x is visible not because it is run in the scope of f() but because f2 gets it as a closure. That means in f2, all variables will be visible that was in the same scope when it was created.
What the this refers to will be set at invocation time. If you run a function as property of an object like foo.f1() it is considered as a method, and this will be set to the object. But when you just invoke a function like f2() the scope will be the same it was invoked in, in your case it is the window object, because foo is a global in the window object.
In f1 this refers to the hidden f(), therefore if you want f2 also be run in that scope you can use f2.call(this). The argument of .call() will be the this of the function when run.
When your f function returns an object, it doesn't have f2 method. f2 method is an inner method of f and exists only in its scope.
If you use this code:
function f() {
var x = [0];
function f1() {
console.log('f1:', this.x, x);
this.f2();
}
function f2() {
console.log('f2:', this.x, x);
}
return { x:x , f1:f1, f2:f2};
}
var foo = f();
foo.f1();
then this in f1 method will have access to the f2 method of this, and object's f2 method will return the correct x.
You returned this from the function:
{ x : x, f1 : f1 }
This sets the the this objects properties to the above. f2 is not apart of the object so it can't access the this that it refers to.
Is it possible to somehow pass the scope of a function to another?
For example,
function a(){
var x = 5;
var obj = {..};
b(<my-scope>);
}
function b(){
//access x or obj....
}
I would rather access the variables directly, i.e., not using anything like this.a or this.obj, but just use x or obj directly.
The only way to truly get access to function a's private scope is to declare b inside of a so it forms a closure that allows implicit access to a's variables.
Here are some options for you.
Direct Access
Declare b inside of a.
function a() {
var x = 5,
obj = {};
function b(){
// access x or obj...
}
b();
}
a();
If you don't want b inside of a, then you could have them both inside a larger container scope:
function container() {
var x, obj;
function a(){
x = 5;
obj = {..};
b();
}
function b(){
// access x or obj...
}
}
container.a();
These are the only ways you're going to be able to use a's variables directly in b without some extra code to move things around. If you are content with a little bit of "help" and/or indirection, here are a few more ideas.
Indirect Access
You can just pass the variables as parameters, but won't have write access except to properties of objects:
function a() {
var x = 5,
obj = {};
b(x, obj);
}
function b(x, obj){
// access x or obj...
// changing x here won't change x in a, but you can modify properties of obj
}
a();
As a variation on this you could get write access by passing updated values back to a like so:
// in a:
var ret = b(x, obj);
x = ret.x;
obj = ret.obj;
// in b:
return {x : x, obj : obj};
You could pass b an object with getters and setters that can access a's private variables:
function a(){
var x = 5,
obj = {..},
translator = {
getX : function() {return x;},
setX : function(value) {x = value;},
getObj : function() {return obj;},
setObj : function(value) {obj = value;}
};
b(translator);
}
function b(t){
var x = t.getX(),
obj = t.getObj();
// use x or obj...
t.setX(x);
t.setObj(obj);
// or you can just directly modify obj's properties:
obj.key = value;
}
a();
The getters and setters could be public, assigned to the this object of a, but this way they are only accessible if explicitly given out from within a.
And you could put your variables in an object and pass the object around:
function a(){
var v = {
x : 5,
obj : {}
};
b(v);
}
function b(v){
// access v.x or v.obj...
// or set new local x and obj variables to these and use them.
}
a();
As a variation you can construct the object at call time instead:
function a(){
var x = 5,
obj = {};
b({x : x, obj: obj});
}
function b(v){
// access v.x or v.obj...
// or set new local x and obj variables to these and use them.
}
a();
Scope is created by functions, and a scope stays with a function, so the closest thing to what you're asking will be to pass a function out of a() to b(), and that function will continue to have access to the scoped variables from a().
function a(){
var x = 5;
var obj = {..};
b(function() { /* this can access var x and var obj */ });
}
function b( fn ){
fn(); // the function passed still has access to the variables from a()
}
While b() doesn't have direct access to the variables that the function passed does, data types where a reference is passed, like an Object, can be accessed if the function passed returns that object.
function a(){
var x = 5;
var obj = {..};
b(function() { x++; return obj; });
}
function b( fn ){
var obj = fn();
obj.some_prop = 'some value'; // This new property will be updated in the
// same obj referenced in a()
}
what about using bind
function funcA(param) {
var bscoped = funcB.bind(this);
bscoped(param1,param2...)
}
No.
You're accessing the local scope object. The [[Context]].
You cannot publicly access it.
Now since it's node.js you should be able to write a C++ plugin that gives you access to the [[Context]] object. I highly recommend against this as it brings proprietary extensions to the JavaScript language.
You can't "pass the scope"... not that I know of.
You can pass the object that the function is referring to by using apply or call and send the current object (this) as the first parameter instead of just calling the function:
function b(){
alert(this.x);
}
function a(){
this.x = 2;
b.call(this);
}
The only way for a function to access a certain scope is to be declared in that scope.
Kind'a tricky.
That would lead to something like :
function a(){
var x = 1;
function b(){
alert(x);
}
}
But that would kind of defeat the purpose.
As others have said, you cannot pass scope like that. You can however scope variables properly using self executing anonymous functions (or immediately executing if you're pedantic):
(function(){
var x = 5;
var obj = {x:x};
module.a = function(){
module.b();
};
module.b = function(){
alert(obj.x);
};
}());
a();
I think the simplest thing you can do is pass variables from one scope to a function outside that scope. If you pass by reference (like Objects), b has 'access' to it (see obj.someprop in the following):
function a(){
var x = 5;
var obj = {someprop : 1};
b(x, obj);
alert(x); => 5
alert(obj.someprop); //=> 'otherval'
}
function b(aa,obj){
x += 1; //won't affect x in function a, because x is passed by value
obj.someprop = 'otherval'; //change obj in function a, is passed by reference
}
You can really only do this with eval. The following will give function b function a's scope
function a(){
var x = 5;
var obj = {x};
eval('('+b.toString()+'())');
}
function b(){
//access x or obj....
console.log(x);
}
a(); //5
function a(){
this.x = 5;
this.obj = {..};
var self = this;
b(self);
}
function b(scope){
//access x or obj....
}
function a(){
var x = 5;
var obj = {..};
var b = function()
{
document.println(x);
}
b.call();
}
Have you tried something like this:
function a(){
var x = 5;
var obj = {..};
b(this);
}
function b(fnA){
//access x or obj....
fnA.obj = 6;
}
If you can stand function B as a method function A then do this:
function a(){
var x = 5;
var obj = {..};
b(this);
this.b = function (){
// "this" keyword is still === function a
}
}
function F() {
function C() {
return this;
}
return C();
}
var o = new F();
Break down the component elements.
Suppose you were to do this:
function C() {
return this;
}
var o = C();
There is clearly no object context here, so this is window.
Wrapping that setup in a constructor doesn't change the fact that there isn't any object involved in the context of a straightforward call to C().
function C() is not a method of F, what you need to do is something like this:
function F() {
this.C = function() {
return this;
}
return this.C();
}
var o = new F();
Although that is a bit convoluted, when you could just do this to achieve the same thing:
function F() {}
var o = new F();
C() is not a method of the f object. As in, you can't call o.C();. If that makes sense. and because you return the return value of C() instead of a new instance of C it returns the window object.
function F() { return this; } will also return window. So will var obj = this. It't the value of "this" whenever "this" has no other value.
I'm trying to maintain state on an object by doing something like this:
obj = function() {
this.foo = undefined;
this.changeState = function () {
(function () { this.foo = "bar" })(); // This is contrived, but same idea.
};
};
I want to set the instance variable foo to "bar" when I call the changeState method.
For instance:
o = new obj();
o.changeState();
alert(o.foo); // This should say "bar"
As far as I can tell, what is happening is that "this" in the inner anonymous function is pointing to window. I'm not sure what's going on.
Am I on the right track? Is there a better approach?
this topic comes up a lot, but it's hard to serach for since "this" is removed from SO searches.
Basically, in JavaScript, this always refers to the calling object, not the context object. Since here we call o.changeState() from the global scope, this refers to window.
You actually don't need the inner function for the closure to work in this case - the changeState function itself is enough to close a lexical scope.
obj = function()
{
var self = this;
this.foo = undefined;
this.changeState = function()
{
self.foo = "bar";
}
}
Unless you specify a this context when calling a function the default will be the global (which in browsers is window).
Alternatives are:-
obj = function() {
this.foo = undefined;
this.changeState = function () {
(function () { this.foo = "bar" }).call(this); // This is contrived, but same idea.
};
};
or:-
obj = function() {
var self = this;
this.foo = undefined;
this.changeState = function () {
(function () { self.foo = "bar" })(); // This is contrived, but same idea.
};
};
function obj() {
this.foo = undefined;
this.changeState = function () { this.foo = "bar" };
};
var o = new obj();
o.changeState();
alert(o.foo);
works for me. I'm not sure why you would want to use a self-invoking function just to assign a function reference, nor why you use a function expression for your constructor rather than a function declaration.
I figured it out. Just needed to save a reference to the current context and use that in the inner anonymous function:
obj = function() {
this.foo = undefined;
var self = this;
this.changeState = function () {
(function () { self.foo = "bar" })();
};
};