this context bug in javascript - why doesn't this trigger a bug? - javascript

I thought this was suppose to trigger a bug when calling a function from within a function using the keyword this. Running Chrome 37.0
S = function () {
this.x = "test";
this.test1 = function () {
console.log("test1");
this.test2();
};
this.test2 = function () {
console.log(this); // output is s object, thought 'this' suppose to be global?
console.log("test2");
};
};
s = new S();
s.test1();
Edit:
I mixed it up with this code:
s = function () {
console.log(this);
var t = function () {
console.log(this);
};
t();
};
x = new s();

Calling a function as part of an expression where you get the function reference from an object property calls the function with this set to the object you got the property from.
So your code:
s.test1();
...will call test1 setting this equal to the object referenced by s, because the call is part of an expression getting the test1 function reference from a property on the object s refers to.
Then in test1, when you do:
this.test2();
...it calls test2 setting this equal to the object referenced by this, because the call is part of an expression getting the test2 function reference from a property on the object this refers to.
Where you'd run into a problem with this not being set correctly would be if you didn't call test1 or test2 via an object property, like this:
var f = s.test1;
f();
Then, within the call to test1, this would be the global object (in loose mode) or undefined (in strict mode). The same sort of thing happens when passing a function as an argument:
foo(s.test1);
If foo calls the function its first argument relates to, we get the same thing (this = global object or undefined).
Since you're not doing that, though, that doesn't happen.
The key thing here is how the function is called, not where it's defined (inside another function or not).
More on this in How Does The this Keyword Work? here on SO, and in Mythical methods and You must remember this on my blog.

Related

Nested .bind not working as expected

Unfortunately .bind has been giving me grief when creating more complex closures.
I am quite interested in why .bind seems to work differently once you nest functions.
For example :
function t(){
t = t.bind({}); //correctly assigns *this* to t
function nested_t(){
nested_t = nested_t.bind({}); // fails to assign *this* to nested_t
return nested_t;
}
return nested_t();
}
//CASE ONE
alert(t());
// alerts the whole function t instead of nested_t
//CASE TWO
aleft(t.call(t));
// alerts the global object (window)
In both cases I was expecting a behavior like this:
function t(){
var nested_t = function nested_t(){
return this;
};
return nested_t.call(nested_t);
}
alert(t.call(t));
If someone could explain the behavior of .bind in the first (and/or) second case it would be much appreciated!
So, i'm not entirely reproducing your issue here (both cases return the global object), but i'll try and explain the code as i see it.
function t(){
t = t.bind({}); //correctly assigns *this* to t
function nested_t(){
nested_t = nested_t.bind({}); // fails to assign *this* to nested_t
return this;
}
return nested_t();
}
//CASE ONE
alert(t());
Let's take it step by step.
First, the function t() is defined. Then, upon call, it gets overwritten with a clean context. However, i don't see any usage of this context.
Now, a nested function (nested_t) is defined. Upon call, it is overwritten with a clean context. It then returns the context it had when it was called.
Back to t(). You then return the result of nested_t(), not nested_t itself. In the original function call, nested_t is still being called with global context.
Therefore, when you run t(), it returns the global object.
How your code works
It's very unclear, what your code is trying to do. You can find the documentation for .bind() here. It looks like you might be somehow misunderstanding what this is and how to use it. Anyway, what happens when you run your code is this:
A t function is created in global scope.
[case one] The t function is called.
Global scope t is replaced with a new value (original t bound to a specific context - anonymous empty object), which doesn't affect the current call in any way. Also, while the global t is overwritten, the local t is behaving as read-only. You can check it out by trying the following code: (function foo () { return (function bar () { bar = window.bar = 'baz'; return bar; })(); })() and comparing return value with window.bar.
The same thing happens with nested_t in the nested context (instead of global context).
Result of nested_t call is returned. nested_t returns the context it was called with, which was window, as no context was specified. Specifically, it was not called with an empty object context, because the .bind() inside didn't affect the call itself.
[case two] The exact same thing happens once again. Now you're just calling t with itself as context. Since t doesn't use its context (this) anywhere in its code, nothing really changes.
What your misconceptions might be
Basically, you're mixing up two things - function instance and function call context. A function is a "first-class citizen" in JavaScript - it's an object and you can assign values to its properties.
function foo () {
foo.property = 'value';
}
foo(); // foo.property is assigned a value
This has nothing to do with function call context. When you call a function a context is assigned to that call, which can be accessed using this (inside function body)
function foo () {
this.property = 'value';
}
var object = {};
foo.call(object); // object.property is assigned a value
When you use .bind(), you just create a new function with the same code, that is locked to a specific context.
function foo () {
this.property = 'value';
}
var fixedContext = {},
object = {};
bar = foo.bind(fixedContext);
foo.call(object); // fixedContext.property is set instead of object.property
But in this case, there are also function instances foo and bar, which can also be assigned properties, and which have nothing to do with contexts of calls of those functions.
Let's look at how bind works. First, one level of nesting:
var foo = function() { return this.x; };
alert(foo()); // undefined
alert(foo.bind({x: 42})()); // 42
Now we can add the next level of nesting:
var bar = function() { return foo.bind(this)(); };
alert(bar()); // undefined
alert(bar.bind({x: 42})());
We pass our this context to foo with - guess what? - bind. There is nothing different about the way bind works between scopes. The only difference is that we've already bound this within bar, and so the body of bar is free to re-bind this within foo.
As a couple of commenters have noted, functions that overwrite themselves are a huge code smell. There is no reason to do this; you can bind context to your functions when you call them.
I highly, highly recommend reading the documentation on bind, and trying to understand it to the point where you can write a basic version of Function.prototype.bind from scratch.

Function object, context and this [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
this operator in javascript
The term context is bit confusing me.If i declare a function within a function i.e nested function and execute there itself,like below...
function foo(){
function fo(){
alert(this);
}
fo();
}
the this keyword should point to the function object rather than window since function fo() is within its parent function.Since function is also an javascript object,than why the this keyword is traversing the function object and pointing to window?
Also this keyword points to the current object on which the function operates ,so function object is the object on which the nested function operates.
If you just call foo() in the top level, it is identical to window.foo().
And window is the actual context of foo, so, this points to the window object.
Adding to what dlutxx said. If you have a function (in the global space) and you simply call it like foo() the context is the window itself (since the function is a member of the window object). However, if you use the new keyword for getting a new instance of the function, this will refer to the function object.
function foo() {
alert(this);
}
foo(); // "this" inside the function will be window
new foo(); // "this" inside the function will be the function object.
If you want to have a custom value for this inside the function, you can call it using .call() like:
foo.call(x); // "this" inside the function will be x
Example code for your case:
function foo(){
function fo(){
alert(this);
}
fo(); // "this" is window
new fo(); // "this" is the function object
fo.call('x'); // "this" is 'x'
}
If you randomly use this inside of a function which is NOT a constructor, then you will get one of a few different results:
function callThis () { return this; }
callThis(); // returns window object
var Bob = { func : callThis };
Bob.func(); // returns Bob
callThis.call(Bob); // returns Bob
Call is a method which is used to determine the context of the call.
If the call's context can not be determined by:
a. What's in front of the "." (Bob.func();)
b. What's explicitly passed into .call(), .apply() or .bind()
Then it's set to window.
That is how context is resolved.
So if you have a specific object in mind for this, then your solutions are as follows:
function objMethod () {
var self = this;
function doStuff () {
self.otherFunc();
self.otherProperty = "bob";
}
doStuff();
}
var myObj = { myMethod : objMethod };
myObj.myMethod();
myObj calls objMethod with the context set to myObj.
objMethod saves a reference to the current context (myObj) as self. doStuff uses the reference to modify the properties of the referenced object.
function outer () {
function inner () { this.property = "Bob"; }
inner.call(this);
}
var obj = {};
outer.call(obj);
Here, outer is passed a context, using .call().
Then inner is passed the this of outer, again, using .call()
var bob = { name : "Bob" };
function sayName () { console.log(this.name); }
var bobFunc = sayName.bind(bob);
bobFunc();
Here, we use .bind() to create a version of sayName where this is always set to bob.
You can feel free to mix and match these systems all you'd like (and when dealing with async programming, you likely will).
my understanding is that although function fo() is defined in the scope of function foo(), which means that it is not accessible from outside of foo unless you return it, the rules that apply to the value of this when you call this internal function, are still the same as if you called any other function.
function f() {
function g() {
console.log(this)
}
console.log(this);
g();
g.apply(this);
}
f() // => Window, Window, Window
f.apply(this) // => Window, Window, Window
f.apply({}) // => Object, Window, Object

What the difference between those two?

Is there any difference between these two:
var test1 = function () {
this.method1 = function() {}
}
and
var test2 = function() {};
test2.method1 = function() {};
The first snippet takes this object, whatever it is, and assigns a function to its slot (field) named method1. this can represent different objects, depending upon how test1 is called:
when called as a standalone function -- test1() -- this will be window
when called as a constructor -- new test1() -- this refers to the object being created
when called via call or apply -- test1.apply(someObject) -- this refers to the argument
The second snippet takes the object test2 and assigns a function to its slot named method1.
The first way is a constructor that creates more objects and needs to have the new keyword:
var mytest1 = new test1();
mytest1.method1();
The second way is ready to use right away:
test2.method1();
Assuming syntax was correct, the first is a constructor that gives all test1 objects created via new test1() a method called method1. The second just adds a function to the constructor object. In javascript, functions are objects which can have properties (including methods).
The first version actually creates a method available to all objects instantiated like so:
var o = new test1();
o.test1();
The second simply attached a function as an attribute on the test2 function. If you're familiar with other class-based OO languages, this works kinda like a static method. You will not have access to the this pointer in the second example.
The first one:
var test1 = function () {
this.method1 = function() {}
}
Defines the function "test1". Once (and only when) "test1" is called, "this.method1" will be defined as a function, that does nothing.
The second:
var test2 = function() {};
test2.method1 = function() {};
Create the function "test2" and at the same time defines the function "test2.method1", without the need to invoke the first function.
The first one sets the method1 property on whatever invokes test1().
The second one defines an empty function and sets the method1 property on test2

Javascript: why "this" inside the private function refers to the global scope?

Consider the following code:
function A() {}
A.prototype.go = function() {
console.log(this); //A { go=function()}
var f = function() {
console.log(this); //Window
};
f();
}
var a = new A();
a.go();
Why does 'this' inside function 'f' refers to the global scope? Why it is not the scope of function 'A' ?
JavaScript has a different concept of what the special name this refers to
than most other programming languages do. There are exactly five different
ways in which the value of this can be bound in the language.
The Global Scope
this;
When using this in global scope, it will simply refer to the global object.
Calling a Function
foo();
Here, this will again refer to the global object.
ES5 Note: In strict mode, the global case no longer exists.
this will instead have the value of undefined in that case.
Calling a Method
test.foo();
In this example, this will refer to test.
Calling a Constructor
new foo();
A function call that is preceded by the new keyword acts as
a constructor. Inside the function, this will refer
to a newly created Object.
Explicit Setting of this
function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // array will expand to the below
foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3
When using the call or apply methods of Function.prototype, the value of
this inside the called function gets explicitly set to the first argument
of the corresponding function call.
As a result, in the above example the method case does not apply, and this
inside of foo will be set to bar.
Note: this cannot be used to refer to the object inside of an Object
literal. So var obj = {me: this} will not result in me referring to
obj, since this only gets bound by one of the five listed cases.
Common Pitfalls
While most of these cases make sense, the first one is to be considered another
mis-design of the language because it never has any practical use.
Foo.method = function() {
function test() {
// this is set to the global object
}
test();
}
A common misconception is that this inside of test refers to Foo; while in
fact, it does not.
In order to gain access to Foo from within test, it is necessary to create a
local variable inside of method which refers to Foo.
Foo.method = function() {
var that = this;
function test() {
// Use that instead of this here
}
test();
}
that is just a normal variable name, but it is commonly used for the reference to an
outer this. In combination with closures, it can also
be used to pass this values around.
Assigning Methods
Another thing that does not work in JavaScript is function aliasing, which is
assigning a method to a variable.
var test = someObject.methodTest;
test();
Due to the first case, test now acts like a plain function call; therefore,
this inside it will no longer refer to someObject.
While the late binding of this might seem like a bad idea at first, in
fact, it is what makes prototypal inheritance work.
function Foo() {}
Foo.prototype.method = function() {};
function Bar() {}
Bar.prototype = Foo.prototype;
new Bar().method();
When method gets called on a instance of Bar, this will now refer to that
very instance.
Disclaimer: Shamelessy stolen from my own resources at http://bonsaiden.github.com/JavaScript-Garden/#function.this
The reason why is you are invoking f as a function and not a method. When invoked as a function this is set to window during the execution of the target
// Method invocation. Invoking a member (go) of an object (a). Hence
// inside "go" this === a
a.go();
// Function invocation. Invoking a function directly and not as a member
// of an object. Hence inside "f" this === window
f();
// Function invocation.
var example = a.go;
example();
The scope of all functions is window.
To circumvent that, you can do this:
function A() {}
A.prototype.go = function() {
var self = this;
console.log(self); //A { go=function()}
var f = function() {
console.log(self); //A { go=function()}
};
f();
}
Because function f() is not called without any object reference. Try,
f.apply(this);

this value in JavaScript anonymous function

Can anybody explain to me why A is true and B is false? I would have expected B to be true as well.
function MyObject() {
};
MyObject.prototype.test = function () {
console.log("A", this instanceof MyObject);
(function () {
console.log("B", this instanceof MyObject);
}());
}
new MyObject().test();
update:
since ecmascript-6 you can use arrow functions which would make it easy to refer to MyObject like this:
function MyObject() {
};
MyObject.prototype.test = function () {
console.log("A", this instanceof MyObject);
(() => {//a change is here, which will have the effect of the next line resulting in true
console.log("B", this instanceof MyObject);
})(); //and here is a change
}
new MyObject().test();
Inside of your anonymous function this is the global object.
Inside of test, this is the instance of MyObject on which the method was invoked.
Whenever you call a function like this:
someFunction(); // called function invocation
this is always the global object, or undefined in strict mode (unless someFunction was created with bind** — see below)
Whenever you call a function like this
foo.someMethod(); //called method invocation
this is set to foo
**EcmaScript5 defines a bind function that allows you to create a function that has a pre-set value for this
So this
var obj = { a: 12 };
var someFunction = (function () { alert(this.a); }).bind(obj);
someFunction();
Causes someFucntion to be invoked with this equal to obj, and alerts 12. I bring this up only to note that this is a potential exception to the rule I mentioned about functions invoked as
someFunction();
always having this equal to the global object (or undefined in strict mode)
this is special. It refers to the object that the function is being called on behalf of (most commonly via dot syntax).
So, in the case of A, the function is being called on behalf of a new MyObject object. B is in a different function that isn't explicitly being called on behalf of any object, so this defaults to the global object (window).
In other words, this changes depending on how the function is called, not where or how it is defined. The fact that you're using an anonymous function (defined inside another function) is coincidental and has no effect on the value of this.
In the anonymous function, this is bound to the global object (window in a browser environment).
There are various ways of accessing the instance:
var self = this;
(function () {
console.log("B", self instanceof MyObject);
}());
or
(function () {
console.log("B", this instanceof MyObject);
}).call(this);
this is set based on how you call the function.
Your anonymous function is a normal function call, so this is the global object.
You could write (function() { ... }).call(this) to explicitly call it with your this.

Categories

Resources