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
Related
I'm using Chrome v22.0.1229.94 m, not that it should matter, but just in case :-)
Portability is of no concern to me. As long as it works with Chrome (and Safari) I'm happy.
I have two functions, foo and bar:
var foo = function() {
...
}
function bar() {
...
}
then if I create objects using them:
f1 = new foo();
b1 = new bar();
I can get the constructor's name for bar, but nor for foo:
> f1.constructor.name ==> ""
> b1.constructor.name ==> "bar"
yet in both cases DevTools console will show the names "foo" and "bar" when I inspect the variables f1 and b1.
How do I extract the name foo for f1 as DevTools is able to?
V8 can perform function name inference at the parsing stage, exposing this information via its APIs. You will not be able to extract this info using the normal object properties.
In the case for foo, you're creating a function expression. That means, you're assigning an anonymous function to a variable.
You can't resolve the function name programatically like that, unless you give the function a name and create a "named function expression".
var foo = function foo() {
...
}
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
Note: the code in this question was run in Chrome Console.
I encountered this problem when I was doing the JS-puzzler, question 21 (well.. it didn't gave a ordering though). The question ask about the result of:
var x = [].reverse; x();
and the answer is window. As the answer states:
[].reverse will return this and when invoked without an explicit receiver object it will default to the default this AKA window.
Based on this understanding, I wrote a bit of code to test:
function Bar(){
var x = [].reverse;
console.log(x());
}
new Bar();
And guess what.. this code raise an error:
TypeError: Array.prototype.reverse called on null or undefined
I want to ask why the x() called in the new Bar is not showing the this object, but raising exception instead?
When you call a function as in x(), the this pointer will be set to either window or undefined (in strict mode). It is the method of calling the function that determines that value of this.
The methods of calling that let you control the value of this are:
x.call(xxx)
x.apply(xxx)
foo.x()
Calling as just:
x()
will set this to the default value which is window in normal JS mode orundefined in strict mode.
The other thing you may want to understand is that once you do:
var x = [].reverse;
Then, x only holds a reference to the reverse() function. There is no association at all with the [] that you originally used. So, when you call x(), you're just calling the reverse() function with no object association and thus this gets set to the default value which is window in normal JS mode or undefined in JS strict mode.
It's because you're getting a function reference without the scope it executes on. The reverse function, in its source, references this. If you call a function properly:
var obj = {
run: function() { console.log(this) }
};
obj.run(); // this will be obj, as expected
But if you call it like this:
var broken = obj.run;
broken(); // this will be the global object
It's just the way javascript execution works in regards to scope. Calling a function with dot notation on an object will make this the object it's on.
If you're in a modern browser, you can bind the value of this to the right thing:
var arr = [1,2,3];
var boundReverse = arr.reverse.bind( arr );
boundReverse() // [3, 2, 1]
The original question is about the output of the following code.
var x = [].reverse;
x();
But the output of the snippet above is
Uncaught TypeError: Array.prototype.reverse called on null or undefined
Actually the equivalent call as follow gives the same error:
Array.prototype.reverse.call();
So, The answer of the question on JavaScript Puzzler is not correct. Though the Array.prototype.reverse return this, the snippet will still throw an error, caused by lacking of an associating object.
This question can be used to test, if the tested one did understand the function definition via var, in which the var only holds the methods and drops the associating object.
Solution: (bind the associating object by calling)
// An associated object can be bound as below.
var x = [].reverse;
x.bind([1,2,3])();
// output : [3,2,1]
// equivalent to
Array.prototype.reverse.call([1,2,3]);
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
I'm using Chrome v22.0.1229.94 m, not that it should matter, but just in case :-)
Portability is of no concern to me. As long as it works with Chrome (and Safari) I'm happy.
I have two functions, foo and bar:
var foo = function() {
...
}
function bar() {
...
}
then if I create objects using them:
f1 = new foo();
b1 = new bar();
I can get the constructor's name for bar, but nor for foo:
> f1.constructor.name ==> ""
> b1.constructor.name ==> "bar"
yet in both cases DevTools console will show the names "foo" and "bar" when I inspect the variables f1 and b1.
How do I extract the name foo for f1 as DevTools is able to?
V8 can perform function name inference at the parsing stage, exposing this information via its APIs. You will not be able to extract this info using the normal object properties.
In the case for foo, you're creating a function expression. That means, you're assigning an anonymous function to a variable.
You can't resolve the function name programatically like that, unless you give the function a name and create a "named function expression".
var foo = function foo() {
...
}