When I run in the console, I don't quite follow why it yields a result of zero. I thought both MyObject and myFunc are global. What concept am I missing to understand this properly?
myObject = {
length: 400,
};
function myFunc () {
return console.log(this.length);
}
myFunc(myObject.length); // equals zero
It's showing you the value of window.length (which is the number of frames/iframes in the document). To have myFunc show you the value of the length of the object you pass into it, you'd have to use that argument:
function myFunc (obj) {
return console.log(obj.length);
}
If you're trying to explore implicit globals (your myObject is an implicit global; they're a Bad Thing(tm)), then myFunc should be called with no arguments and should use myObject.length or possibly this.myObject.length (which come to the same thing).
You're passing the object as a parameter, but you're not receiving it in the function. this in the context of myFunc is not the object myObject. It is the window object.
To achieve what you're trying to do, modify your code like so:
myObject = {
length: 400,
};
function myFunc (obj) {
return console.log(obj.length);
}
myFunc(myObject); // equals zero
Note:
To verify that this is the window object, see this fiddle where I've modified your console line to be return console.log(this);. The console outputs the Window object.
Demonstration Fiddle
Related
I've got this interview question and can't really get what the difference between fn() an arguments[0]() since they both reference to the same function.
var length = 10;
function foo() {
console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {
fn(); // TypeError: Cannot read property 'length' of undefined
arguments[0](); // 2
}
};
obj.method(foo, 1);
Ok, so when calling arguments[0](), in foo it's context (this) will be equal to function arguments - [Arguments] { '0': [Function: foo], '1': 1 }. But how is this happend?
Consider the following code:
function foo() {
console.log(this.bar);
}
const obj = {
bar: "foobar",
myFunction: foo
}
obj.myFunction(); // foobar
In the above, the this in the function foo gets bound to the calling context of foo, in the case above, that is the object obj, and so this inside of the function foo will refer to obj.
In your case, arguments is an object. It has a bunch of properties such as its length as well as numeric properties to represent indexes for the arguments passed into the function. For example, you could (roughly) make your own arguments object like so:
function foo() {
console.log(this.length);
}
const myArguments = {
0: foo,
length: 2
}
myArguments[0](); // 2
Notice that the above myArguments[0]() is using the same idea of calling a function from the first code snippet (obj.myFunction()), except we are using bracket notation (arguments[0]) rather than dot-notation (arguments.0) to access and call the function stored at the property 0 from the object myArguments. Thus, the calling context for foo in this case is myArguments, and as a result that is what this gets bound to within the function foo.
The same idea above applies to your code. When you call fn() without an explicit context the this within your foo() function will become undefined (if in strict-mode), thus causing your error:
TypeError: Cannot read property 'length' of undefined
However, when using arguments[0], the this gets bound to the arguments object, much like in the above two examples.
The this value used by an execution context depends on how a function was called.
1. fn() // TypeError: Cannot read property 'length' of undefined
2. arguments[0]() // 2
Line 1 shows a direct function invocation. For this style the this value will be undefined in strict mode and the global object in non-strict mode.
Line 2 shows a function being invoked as a method. It is a bit of a trick question because we are more used to seeing the dot operator used with methods, but the bracket property accessor notation works similarly. When you invoke a function as a method, the this value is set to be the object the method is invoked on. This behavior is designed to support object-oriented style programming.
It's akin to writing arguments.0(), but the JS syntax does not permit this sequence (presumably due to ambiguity with the decimal place syntax).
Sneaky interview question!
here obj work like an array, get value on given position and call it as a function
var length = 10;
function foo1() {
console.log(length);
}
function foo2() {
console.log(this.length);
}
const obj = {
length: 5,
0: foo1,
1: foo2,
};
obj[0](); // 10
obj[1](); // 5
I did an JavaScript experiment in browser's console -
First I created a new object foo as following
var foo = {
bar: function() { return this.baz; },
baz: 1
};
Now when I run the following code again in console it returns "number"
(function(){
return typeof foo.bar();
})();
But when I run following anonymous function it returns "undefined"
(function(){
return typeof arguments[0]();
})(foo.bar);
As far as I know arguments[0] in above function return foo.bar (also proved by the following example) then why the above code returns "undefined" instead of "number"?
When I run
(function(){
return arguments[0];
})(foo.bar);
returns function () { return this.baz; }
Also
(function(){
return typeof arguments[0];
})(foo.bar());
Returns "number" then why not
(function(){
return typeof arguments[0]();
})(foo.bar);
returns the same? Is there any fundamental law in JavaScript that is working here?
this depends on how you call the function. When using dot notation, JavaScript sets the context of this to the receiver. In your case there is no receiver, but a reference to the function, so you lost the context. You have to pass it explicitly:
arguments[0].call(foo);
arguments[0] is the same function object as foo.bar but the value of this is dynamic. In foo.bar(), this gets assigned to foo because you used foo. (dot notation). But in arguments[0]() there's no dot (no receiver) so this is the default value, or window.
It's the same function but different invocation.
Let me simplify the problem ...
var foo = {
bar: function() { return this.baz; },
baz: 1
};
var ref = foo.bar;
console.log(typeof ref()); // undefined
console.log(typeof foo.bar()); // number
It is because 'this' inside the function object 'bar' does not always refer to 'foo'. It changes on how you call it. If you call it from an object not foo it will show undefined. Note that ref is not foo but foo.bar.
Now if you change foo to the following it will give 'number' output in both cases ...
var foo = {
bar: function() { return foo.baz; },
baz: 1
};
Note that
console.log(ref === foo.bar); // true
but foo.bar() is not equal to ref() (In first case) because when you call foo.bar() the javascript engine passes foo as 'this' but when you call ref() which is originally window.ref(), it passes window object (or other global object in case of non-browser environment) as 'this'
Elaboration on elclanrs' answer.
foo.bar is a method; an instruction of how to do something. In object-oriented programming languages, the only object that can use that instruction is a foo or an object related to foo; but in JavaScript, anybody can try to run it if the code asks them to.
In your second anonymous function, you are getting a method to run, running it, and returning the type of the result. However, it's not a foo that is running this function; it's anonymous, so the window is the object that's running it. The window runs foo, which tries to return this.baz; however, the window doesn't HAVE a baz, so that's why you're getting undefined.
To test it further, try setting window.baz and see if you get the right result, and also try elclanrs' suggestion of using the call() method to ensure it gets called from a foo's scope.
EDIT
You're right, the type of arguments[0] and foo.bar IS the same; they're both "function". I think the confusion is over JavaScript's treatment of functions as first-class objects.
If you're familiar with object-oriented languages like Java or C++, then you would expect that when you call bar, it's always being called by a foo that has a baz property; however, this isn't the case in JavaScript. Any function can be called by ANY object, which means the result may or not make sense.
The difference between the two, as elclanrs says, is all about the .. Let's say I made my own object phew = {baz: 44}. I could, validly, "steal" a method from foo like this: phew.myMethod = foo.bar. Now, phew knows the instructions contained in bar, and if I call phew.myMethod(), I would get 44 as my result because phew is calling the method, and phew's baz is 44; it doesn't matter where the method is defined! All that matters is what the method says to do, and bar says to return the baz of whoever called it.
So now, going back to your code, you're calling arguments[0](). It does seem like it should be the same, but because functions are first-class objects, when you passed it as a parameter, all you really passed was a function called bar. When you called arguments[0](), it was like calling bar(), which is different from calling foo.bar() just like it's different from calling phew.myMethod(), even though they all are exactly the same function.
For more info, try this SO post
var foo = function () {};
foo.a = "an attribute"; // set attribute to prove foo is an object
console.log(foo) // log shows: function () {};
I thought function foo is an object, but why console.log in Chrome shows "function () {}" rather than an inspectable Object? Is there anyway to show inspectable Object when logging a function?
When you call console.log(foo), the console builds a non normalized display (it's not part of EcmaScript). In most cases (but not for basic objects) it calls the toString function of the argument (but does more work, like adding quotes to string, setting a color, offering object browsing, etc.).
The toString function of a function simply prints the code.
If you want to see all properties, you might do
console.dir(foo);
or (at least on Chrome)
console.log("%O", foo);
You'd see the same phenomenon with other objects having a dedicated toString function.
For example :
var a = new Number(3);
a.b = 4;
console.log(a); // logs just 3
console.dir(a); // lets you see b
Use console.dir() to see the a
>>>>console.log(foo);
function()
>>>>console.dir(foo);
a "an attribute"
prototype Object { }
dystroy is right. function is an object whose toString prints the code.
console.log(foo.a);
would do the trick
I'm having an issue with Javascript object literals.
I would like to reference the object within one of the functions:
var Obj = {
name : "Johnny",
dumb : function() {
alert(this.name);
}
}
Sadly, the "dumb" function is an object as well. So, since dumb() has no
'name' property, it will return as undefined.
How do I get around this?
dumb is a method on your Obj object. When called, this will be set to Obj, and will alert "Johnny"
Try it out
var Obj = {
name : "Johnny",
dumb : function() {
alert(this.name);
}
}
Obj.dumb();
Your code is fine. The call to dumb should be:
Obj.dumb(); // "Johnny"
this in JavaScript is defined entirely by how a function is called, not where the function is defined. If you call a function via an object property, within the call this will refer to the object. So for instance, if you did this:
var f = Obj.dumb;
f(); // "undefined"
...then you get undefined (well, probably), because you haven't set any specific value for this. In the absense of a specific value, the global object is used. (window, on browsers.)
You can also set this by using the call or apply features of JavaScript functions:
var f = Obj.dumb;
f.call(Obj); // "Johnny"
The first argument to call (and to apply) is the object to use as this. (With call, any subsequent arguments are passed to the function, so f.call(Obj, 1); would effectively be Obj.dumb(1);. With apply, the second argument is an array to use as the arguments for the function, so f.apply(Obj, [1]); would effectively be Obj.dumb(1);.)
More reading:
Mythical methods
You must remember this
I think I'm missing the problem here. Your code works fine.
var Obj = {
name : "Johnny",
dumb : function() {
alert(this.name);
}
}
Obj.dumb(); // Alerts 'Johnny'
This is because dumb is called on Obj which is set to this.
EDIT: If you did the following, it would be undefined:
var x = Obj.dumb;
x(); // Alerts ''
This is because this is now window (as the function is not being called on Obj anymore).
You'd have to either .call:
var x = Obj.dumb;
x.call(Obj); // Alerts 'Johnny'
Or .bind (ECMAScript 5, meaning modern browsers only):
var x = Obj.dumb.bind(Obj);
x.call(); // Alerts 'Johnny'
Everything in JS is an object. this is not "the function being called" it is the object it is being called on (unless you use something like apply() to mess with that).
Obj.dumb();
will have this === Obj so this.name will resolve to "Johnny".
Just make sure you call Obj.dumb() and don't do something like:
// This won't work
var foo = Obj.dumb;
foo();
… as, while foo will be the same function as dumb, the context is different (and this will be the default object: window).
Does the value of "this" refer to the global object or the object "o" in the program below?
More importantly, what code could I run to test what the reference of "this" is?
function F() {
function C() {
return this;
}
return C();
}
var o = new F();
It refers to the global object (window).
Edit: Actually, it will refer to both, the global object and o, because they are the same. o will have a reference to the object returned from F() which is the object returned from C() which is the window object ;)
You can call console.log(this) to find out which object it refers to. It should give you a listing of all the methods of the object on the console and you should be able to infer from this which object it is.
For this to work in Firefox, you need Firebug. Don't know for IE.
Update:
#Anurag already showed you how to explicitly set this. If you just want to refer to this of a higher scope, you have to assign it to a variable explicitly. Example:
function F() {
var that = this;
function C() {
console.log(that);
}
C();
}
this refers to the global object in your program. To get this to reference the instance of F, try,
function F() {
function C() {
return this;
}
return C.call(this); // call C with the object of F as a context
}
var o = new F();
On Chrome, you could simply enter the variable to inspect, and its value will get logged. It's similar to doing a console.log(object), but much easier to work with. Here's a screenshot of running this code sample in Chrome. The value of the last statement o is automatically printed, and I printed it once again, just to be sure. It logged DOMWindow which refers to the global window object on the browser.
To add to the other answers:
When a function is called, this is set depending on how it's called. If it's called with myfunc.call or myfunc.apply, then this is set to the first passed argument. If it's called in the 'dotted' form, i.e. myObject.myfunc() then this is set to whatever is before the dot.
There is an exception to this rule, which is that it's possible to bake the value of this in with bind, in which case it will be whatever has been bound. i.e. in var boundfunc = myfunc.bind(myobj); then any time boundfunc is called, it would be like calling myfunc but with this referring to myobj regardless of anything else. Here's an example that does that:
function F() {
var C = function() {
return this;
}.bind(this);
return C();
}
var o = new F();
If none of these cases are applicable, then this is always either the global object (window if you're in a browser), or, if you're in strict mode it's undefined.