I'm not sure where this points in JavaScript. And I give 2 examples.
Can you help me analyze them? Thank you very much.
//exmp1
function f1()
{
alert(this);
function f2()
{
alert(this);
}
f2();
}
f1();
//exmp2
var jsn =
{
name : "b",
func : function() // closure
{
alert(this);
return function()
{
return this;
}
}
}
alert(jsn.func()());
this is different in JavaScript than it is in some other languages like C++ or Java. The value of this in your first example will always be the global object (window, on browsers). this in your second example is the jsn object for the first alert, and window for the second. This is because this is determined entirely by how a function is called, not where it's defined.
If you don't do anything special when calling the function, this is the global object. When you call a function via an object property (jsn.func()), this is set to the object the property came from. (But don't get the wrong impression, func is in no way specially tied to jsn; JavaScript doesn't have methods, just functions; details.) f1 then returns a function, which is called within the final alert; since that call is not via an object property, this is set to the global object.
Some examples:
// Simple function
function foo() {
alert(this === window);
}
foo(); // true, within the call, `this` === `window`
// Object example, and twist at the end
var obj = {
func: function() {
alert(this === obj);
},
};
obj.func(); // true, within the call, `this` === `obj`
obj["func"](); // true, within the call, `this` === `obj`
var f = obj.func; // Not calling it, just getting a reference to the function
f(); // false, within the call `this` !== `obj` (`this` === `window`)
// Creating functions on the fly, returning them, and how that has
// nothing whatsoever to do with how `this` gets set:
var obj = {
func: function() {
return function() {
alert("I'm a generated function");
alert(this === obj);
};
}
};
obj.func()(); // alerts the "I'm a generated function", then false; `this` !== `obj`
obj.bar = obj.func();
obj.bar(); // alerts the "I'm a generated function", then true; `this` === `obj`
There's a second way to control what this is within a function: Use the .call or .apply features of JavaScript functions:
var obj = {
func: function() {
alert(this === obj);
}
};
function foo(a, b) {
alert(this === obj); // Yes, really obj; see below
alert(a);
alert(b);
}
foo(1, 2); // alerts false (`this` !== `obj`), then 1, then 2
obj.func(); // alerts true, `this` === `obj`
foo.call(obj, 3, 4); // alerts true (`this` === `obj`), then 3, then 4
foo.apply(obj, [5, 6]); // alerts true (`this` === `obj`), then 5, then 6
As you can see, the first argument to call or apply is the object to make this within the function call. The only difference between call and apply is how you specify arguments to pass into the target function: With call, you just supply them after the first argument; with apply, you supply them as an array.
And finally, there's a third way: The new keyword. JavaScript has the concept of constructor functions. The purpose of a constructor function is to create instances of objects initialized in a particular way. Here's an example:
function Foo(b) {
this.bar = b;
}
var f = new Foo();
Technically, any function can be used as a constructor function. The convention is to give functions meant to be used with new names starting with a capital letter, just to reinforce that we call them in a special way.
Calling a function via new creates a new object instance and makes that object the this value within the function call. So
function Foo(b) {
alert(this === window);
}
var f = new Foo(); // alerts false, `this` !== `window` (it points to the new object created for the call)
var f = Foo(); // alerts true, `this` === `window` because we didn't use `new`
As you can see, it's important to call a function in the correct way. If it's designed to be used with new, call it via new; if it's not, don't.
(new does more than just create a blank object; the object created has some other aspects set up in a certain way. I won't go into the details here, but I didn't want to leave you with the impression that all it did was create a new object instance.)
In your last example (the function inside json object), this refers to the json object that is holding the function.
In your first example, the first this is referring to the object that is holding f1, it happens to be the global window object. The second this in f2 is also referring to the global object and not to f1, and this is a known bug in javascript, when you have one function defined in another.
A common workaround is this (no pun intended):
function f1() {
alert (this);
var that = this;
function f2() {
alert (that);
}
f2();
}
Notice that if you define a function in a json object, it can still be "moved around" and the context of this will change. For example:
var car1 = {
color: "red",
f: function () { alert (this.color); }
}
car1.f(); // prints "red"
var car2 = {
color: "blue",
}
car2.f = car1.f;
car2.f(); // prints "blue"
In JavaScript "this" always refers to the object which "owns" the function, or rather, the object to which a function was bound via a property at the time it was called. Consider this example:
var f = function() { alert(this); }
f(); // Alerts the "DOM window" (global) object, which
// is implied if there is no explicit owner.
var o = {toString:function(){return "Foo!";}}
o.func = f;
o.func(); // Alerts the "Foo!" object (o) since the
// function then belongs to it as a member.
Now regarding your specific examples, here's what happens:
//exmp1
function f1() {
alert(this);
function f2() {
alert(this);
}
f2(); // Alerts "the global object", since f2
// is not bound to any object's property.
}
f1(); // Alerts "the global object" (probably DOM window)
// for same reason as above.
//exmp2
var jsn = {
name : "b",
func : function() {
alert(this); // Will alert the "jsn" object, since it
// owns the function in its "func" member.
return function() {
return this; // Returns whoever is calling it!
};
}
}
alert(jsn.func()()); // "jsn.func()" returns a function which gets
// called by the global "DOM window" object.
when you use a function as a constructor, this points to the object you are constructing.
function Test() {
this.test = true;
}
t = new Test();
alert(t.test);
Related
var obj = {
bar: function() {
var x = (() => this);
return x;
}
};
// Call bar as a method of obj, setting its this to obj
// Assign a reference to the returned function to fn
var fn = obj.bar();
// Call fn without setting this, would normally default
// to the global object or undefined in strict mode
console.log(fn() === obj); // true
// But caution if you reference the method of obj without calling it
var fn2 = obj.bar;
// Calling the arrow function's this from inside the bar method()
// will now return window, because it follows the this from fn2.
console.log(fn2()() == window); // true
My question is that at last line fn2()() is called but with two sets of closing bracket` which executes the child function. But I searched along web and did not got this double or triple, etc. type of function call anywhere.
So I want ask which part of JavaScript have this topic and how actually it works behind the scene?
In the following code, the first function is not bound to obj, but the second function is, so f() returns fifi and g() returns Mark Twain as expected. But the 3rd attempt, it is by (obj.getCallBack) first, which is now a function, and then it is invoked, essentially it should be the same as the f case. But they do print out Mark Twain instead. Why are they not bound to obj using bind() but still got executed with this pointing to obj?
(the 4th attempt is just a usual invocation of a method, and this should bind to the object on which the method is invoked on).
(tested on the current Chrome, Firefox, and IE 9)
window.name = "fifi";
var obj = {
name: "Mark Twain",
getCallBack: function() {
return this.name;
}
}
var f = obj.getCallBack;
var g = f.bind(obj);
console.log(f);
console.log(f());
console.log(g);
console.log(g());
console.log((obj.getCallBack)());
console.log(obj.getCallBack());
You are forgetting that if a function is called as a property of some object, that object will be the this for the call. So:
obj.getCallBack() //The function referenced by `obj.getCallBack`
//is called as a property of `obj`, so obj will be `this`
//for the call
f() //The function referenced by f, is not called as a property of some object so
//`this` will depend on strict mode.
After these basic rules, the bound function will be invoked, which can be thought of as a proxy function (any shim does this) that uses .call/.apply to explicitly set the context for the target function. So the this value for the proxy function doesn't matter, but behind the scenes it was set by the basic rules.
Edit:
(obj.getCallBack) does not return the function as value, because getValue is not called.. So it is exactly the same as obj.getCallback and the first post applies.
So you can do this and not get an error:
(obj.getCallback) = 5;
As opposed to:
(function(){}) = 5; //invalid assignment
To complement Esailija's answer, the desired effect actually should be:
var obj = {
name: "Mark Twain",
getCallBack: function() {
return function() { return this.name; };
}
}
var f = obj.getCallBack();
var g = f.bind(obj);
console.log(f);
console.log(f());
console.log(g);
console.log(g());
console.log((obj.getCallBack())());
console.log(obj.getCallBack()());
console.log(obj.getCallBack().bind(obj)());
Then in this case, the third attempt will give fifi, and so will the 4th attempt. To get the name inside obj, the fifth attempt binds it and invoke it and will get Mark Twain.
But the method that returns the callBack function should bind it, so let's change the code to:
var obj = {
name: "Mark Twain",
getCallBack: function() {
return (function() { return this.name;}).bind(this); // <-- note here
}
}
and now all attempts, even f(), will return Mark Twain.
I was making a test case to show how 'bind' is necessary for a method to refer to its function in a callback.
But just when I thought I knew JS - the following code works fine - without requiring bind!
pretendThingConstructor = function (greeting) {
this.greeting = greeting;
this.sayHello = function() {
console.log(this.greeting);
};
}
var pretend_thing = new pretendThingConstructor('hello world');
pretend_thing.sayHello();
setTimeout(function() {
pretend_thing.sayHello()
}, 3000);
When I run it - via node, phantomjs, or another JS environment - it works. 'hello world' is printed twice.
I expected the second 'hello world' - the one ran after the timout - to fail, as 'this' would refer to the event, rather than the object. But it works. Why is this?
The this changes depending on how your call the function. If you specify a base object, it will refer to that instead:
pretend_thing.sayHello()
Here pretend_thing is that base object and therefore this still refers to that object. On the other hand, if you had:
var f = pretend_thing.sayHello;
f();
Here this should refer to window object instead.
You can confirm it by putting:
console.log (this instanceof pretendThingConstructor);
Inside your sayHello function. It will print true in both cases.
pretendThingConstructor = function (greeting) {
this.greeting = greeting;
this.sayHello = function() {
console.log(this.greeting);
console.log(this instanceof pretendThingConstructor);
};
}
var pretend_thing = new pretendThingConstructor('hello world');
////////////////////////////
pretend_thing.sayHello();
setTimeout(function() {
pretend_thing.sayHello();
}, 3000);
will output:
true
true
whereas:
var f = pretend_thing.sayHello;
f();
outputs:
false
In the scope of the function 'pretendThingConstructor', 'this' refers to the function itself. When the constructor is run (when you instantiate an object using the 'new' keyword), the sayHello method (which is an anonymous method) will be assigned to the property 'sayHello' on the instantiated object (in your case, pretend_thing).
Because you're calling the 'sayHello' method FROM an instance of the 'pretendThingConstructor' object (pretend_thing), 'this' refers to the object that you're calling the method from, not the context that you're executing in.
You can change the meaning of the 'this' keyword by using the .apply method:
function myHello(){
this.greeting = 'Hello';
this.method = function(){
this.greeting
}
}
function myGoodbye(){
this.greeting = 'Goodbye';
this.say = function(){
console.log( this.greeting );
}
}
var hello = new myHello();
var goodbye = new myGoodbye();
hello.say(); // Outputs 'Hello'
goodbye.say(); // Outputs 'Goodbye'
hello.say.apply( goodbye ); // Outputs 'Goodbye'
Yes in this case the this object of sayHello is pretend_thing because the function knows on which item it is called. The this only gets lost if you're trying to do this:
<-- language: lang-js -->
var say = pretend_thing.say_hello;
setTimeout(function () {
say(); // this is window or null
}, 15)
// You can do something like
function doThings() {
console.log(this.thing);
}
var test1 = { doThings: doThings, thing: 1 };
var test2 = { doThings: doThings, thing: 2 };
test1.doThings(); // <- 1
test2.doThings(); // <- 2
So the context depends on where the function is attached. But you can override this behavior with the bind-thing.
I am creating an AJAX API for a web service and I want to be able to call jQuery-like accessors.
jQuery seems to be able to execute 'jQuery' as a function, but also use it to directly access the object that is the result of the function EG:
jQuery();
jQuery.each({});
This is the trick that I can't seem to pull off:
myAPI('foo'); //output: 'foo'
myAPI('foo').changeBar(); //output: 'foo' 1
myAPI.changeBar(); //Error: not a function
I have seen the answers to similar questions, which are helpful, but don't really answer my question.
#8734115 - Really interesting, but you can't access the methods that were set by f.prototype.
#2953314 - Uses Multiple operations to create object instead of a single function.
here is my code:
(function(window) {
var h = function(foo) {
// The h object is actually just the init constructor 'enhanced'
return new h.fn.init(foo);
};
/**
* Methods defined at protoype.
*/
h.fn = h.prototype = {
constructor: h,
init: function(foo) {
console.log(foo);
return this;
},
splice : function () {},
length : 0,
bar : 0,
changeBar : function() {
this.bar++;
return this.bar;
}
};
h.fn.init.prototype = h.fn;
//Publish
window.myAPI =h;
}( window));
I'm sure I'm missing something simple :(
What jQuery is doing there is using jQuery as both a function and as a pseudo-namespace. That is, you can call jQuery: var divs = jQuery("div"); and you can use properties on it, e.g.: jQuery.each(...);.
This is possible because in JavaScript, functions are first-class objects, and so you can add arbitrary properties to them:
function foo() {
alert("Foo!");
}
foo.bar = function() {
alert("Bar!");
};
foo(); // "Foo!"
foo.bar(); // "Bar!"
That's literally all there is to it.
Within the call to bar, this will be the foo function (because this is determined entirely by how a function is called, not where it's defined). jQuery doesn't use this to refer to itself (usually it uses this to refer to DOM elements, sometimes to other things like array elements; when referring to itself, since it's a single thing, it just uses jQuery).
Now, you might want to ensure that your functions have proper names (whereas the function I assigned to bar above is anonymous — the property has a name, but the function does not). In that case, you might get into the module pattern:
var foo = (function() {
function foo() {
alert("Foo!");
}
function foo_bar() {
alert("Bar!");
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
That pattern also has the advantage that you can have private data and functions held within the scoping function (the big anonymous function that wraps everything else) that only your code can use.
var foo = (function() {
function foo() {
reallyPrivate("Foo!");
}
function foo_bar() {
reallyPrivate("Bar!");
}
function reallyPrivate(msg) {
alert(msg);
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
reallyPrivate("Hi"); // Error, `reallyPrivate` is undefined outside of the scoping function
In your code, you're assigning things to the prototype property of the function. That only comes into play when the function is called as a constructor function (e.g., via new). When you do that, the object created by new receives the function's prototype property as its underlying prototype. But that's a completely different thing, unrelated to what jQuery does where it's both a function and a pseudo-namespace.
You do not need any of that weirdness, to use stuff like $.each
you just attach functions to the function object instead
of the prototype object:
function Constructor() {
if (!(this instanceof Constructor)) {
return new Constructor();
}
}
Constructor.prototype = {
each: function() {
return "instance method";
}
};
Constructor.each = function() {
return "static method";
};
var a = Constructor();
a.each(); //"instance method"
Constructor.each(); //"static method"
what is the this (inside inner functions) referring to in the following code context? Does it point to TimeSpan?
var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
var attrs = "days hours minutes seconds milliseconds".split(/\s+/);
var gFn = function (attr) {
return function () {
return this[attr];
};
};
var sFn = function (attr) {
return function (val) {
this[attr] = val;
return this;
};
};
}
Thanks
The this value is set implicitly depending on how the function is invoked, there are three cases where this happens:
When a reference with no base-object, or a non-reference is invoked:
myFn(); // the myFn reference has no base object
(function () {})(); // non-reference
The this value will point to the global object 1
When a reference contains a base object, for example:
myObj.method();
The this value inside method will point to myObj.
When the new operator is used:
var obj = new Foo();
The this value inside the Foo function, will point to a newly created object that inherits from Foo.prototype.
The this value can be set also explicitly, by using the call and apply methods, for example, with call:
function test(a) {
return alert(this + a);
}
test.call("hello", " world"); // alerts "hello world"
Or with apply if we need to "apply" a set of arguments from an array to a function:
function test(a, b) {
return alert(this + a + b);
}
var args = ["my ", "world "];
test.apply("hello ", args); // alerts "hello my world"
[1] This has changed on the new ECMAScript 5th Strict Mode, now when a function reference with no base object, or a non-reference is invoked (as the first case), the this value will contain undefined.
This was made because when working with constructor functions, people often forgot to use the new operator when calling the constructor.
When that happened, the this value pointed to the global object, and that ended up adding unwanted global properties.
Now on strict mode, this will contain undefined, and if property lookup is made on it (this.foo = 'foo') we will have a nice TypeError exception, instead of having a global foo property.
this refers to the current object, in this case the function you are inside of. Since everything in JavaScript is an object you can modify the attributes of a function object using the this keyword:
var f = function() {
this.key = "someValue";
}
console.log(f.key); // prints "someValue"
So in this case this should point to the function at the deepest scope level, and not TimeSpan.