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() {
...
}
Related
In C++, the language I'm most comfortable with, usually one declares an object like this:
class foo
{
public:
int bar;
int getBar() { return bar; }
}
Calling getBar() works fine (ignoring the fact that bar might be uninitialized). The variable bar within getBar() is in the scope of class foo, so I don't need to say this->bar unless I really need to make it clear that I'm referring to the class' bar instead of, say, a parameter.
Now, I'm trying to get started with OOP in Javascript. So, I look up how to define classes and try the same sort of thing:
function foo()
{
this.bar = 0;
this.getBar = function() { return bar; }
}
And it gives me bar is undefined. Changing the bar to this.bar fixes the issue, but doing that for every variable clutters up my code quite a bit. Is this necessary for every variable? Since I can't find any questions relating to this, it makes me feel like I'm doing something fundamentally wrong.
EDIT: Right, so, from the comments what I'm getting is that this.bar, a property of an object, references something different than bar, a local variable. Can someone say why exactly this is, in terms of scoping and objects, and if there's another way to define an object where this isn't necessary?
JavaScript has no classes class-based object model. It uses the mightier prototypical inheritance, which can mimic classes, but is not suited well for it. Everything is an object, and objects [can] inherit from other objects.
A constructor is just a function that assigns properties to newly created objects. The object (created by a call with the new keyword) can be referenced trough the this keyword (which is local to the function).
A method also is just a function which is called on an object - again with this pointing to the object. At least when that function is invoked as a property of the object, using a member operator (dot, brackets). This causes lots of confusion to newbies, because if you pass around that function (e.g. to an event listener) it is "detached" from the object it was accessed on.
Now where is the inheritance? Instances of a "class" inherit from the same prototype object. Methods are defined as function properties on that object (instead of one function for each instance), the instance on which you call them just inherits that property.
Example:
function Foo() {
this.bar = "foo"; // creating a property on the instance
}
Foo.prototype.foo = 0; // of course you also can define other values to inherit
Foo.prototype.getBar = function() {
// quite useless
return this.bar;
}
var foo = new Foo; // creates an object which inherits from Foo.prototype,
// applies the Foo constructor on it and assigns it to the var
foo.getBar(); // "foo" - the inherited function is applied on the object and
// returns its "bar" property
foo.bar; // "foo" - we could have done this easier.
foo[foo.bar]; // 0 - access the "foo" property, which is inherited
foo.foo = 1; // and now overwrite it by creating an own property of foo
foo[foo.getBar()]; // 1 - gets the overwritten property value. Notice that
(new Foo).foo; // is still 0
So, we did only use properties of that object and are happy with it. But all of them are "public", and can be overwritten/changed/deleted! If that doesn't matter you, you're lucky. You can indicate "privateness" of properties by prefixing their names with underscores, but that's only a hint to other developers and may not be obeyed (especially in error).
So, clever minds have found a solution that uses the constructor function as a closure, allowing the creating of private "attributes". Every execution of a javascript function creates a new variable environment for local variables, which may get garbage collected once the execution has finished. Every function that is declared inside that scope also has access to these variables, and as long as those functions could be called (e.g. by an event listener) the environment must persist. So, by exporting locally defined functions from your constructor you preserve that variable environment with local variables that can only be accessed by these functions.
Let's see it in action:
function Foo() {
var bar = "foo"; // a local variable
this.getBar = function getter() {
return bar; // accesses the local variable
}; // the assignment to a property makes it available to outside
}
var foo = new Foo; // an object with one method, inheriting from a [currently] empty prototype
foo.getBar(); // "foo" - receives us the value of the "bar" variable in the constructor
This getter function, which is defined inside the constructor, is now called a "privileged method" as it has access to the "private" (local) "attributes" (variables). The value of bar will never change. You also could declare a setter function for it, of course, and with that you might add some validation etc.
Notice that the methods on the prototype object do not have access to the local variables of the constructor, yet they might use the privileged methods. Let's add one:
Foo.prototype.getFooBar = function() {
return this.getBar() + "bar"; // access the "getBar" function on "this" instance
}
// the inheritance is dynamic, so we can use it on our existing foo object
foo.getFooBar(); // "foobar" - concatenated the "bar" value with a custom suffix
So, you can combine both approaches. Notice that the privileged methods need more memory, as you create distinct function objects with different scope chains (yet the same code). If you are going to create incredibly huge amounts of instances, you should define methods only on the prototype.
It gets even a little more complicated when you are setting up inheritance from one "class" to another - basically you have to make the child prototype object inherit from the parent one, and apply the parent constructor on child instances to create the "private attributes". Have a look at Correct javascript inheritance, Private variables in inherited prototypes, Define Private field Members and Inheritance in JAVASCRIPT module pattern and How to implement inheritance in JS Revealing prototype pattern?
Explicitly saying this.foo means (as you've understood well) that you're interested about the property foo of the current object referenced by this. So if you use: this.foo = 'bar'; you're going to set the property foo of the current object referenced by this equals to bar.
The this keyword in JavaScript doesn't always mean the same thing like in C++. Here I can give you an example:
function Person(name) {
this.name = name;
console.log(this); //Developer {language: "js", name: "foo"} if called by Developer
}
function Developer(name, language) {
this.language = language;
Person.call(this, name);
}
var dev = new Developer('foo', 'js');
In the example above we're calling the function Person with the context of the function Developer so this is referencing to the object which will be created by Developer. As you might see from the console.log result this is comes from Developer. With the first argument of the method call we specify the context with which the function will be called.
If you don't use this simply the property you've created will be a local variable. As you might know JavaScript have functional scope so that's why the variable will be local, visible only for the function where it's declared (and of course all it's child functions which are declared inside the parent). Here is an example:
function foo() {
var bar = 'foobar';
this.getBar = function () {
return bar;
}
}
var f = new foo();
console.log(f.getBar()); //'foobar'
This is true when you use the var keyword. This means that you're defining bar as local variable if you forget var unfortunately bar will became global.
function foo() {
bar = 'foobar';
this.getBar = function () {
return bar;
}
}
var f = new foo();
console.log(window.bar); //'foobar'
Exactly the local scope can help you to achieve privacy and encapsulation which are one of the greatest benefits of OOP.
Real world example:
function ShoppingCart() {
var items = [];
this.getPrice = function () {
var total = 0;
for (var i = 0; i < items.length; i += 1) {
total += items[i].price;
}
return total;
}
this.addItem = function (item) {
items.push(item);
}
this.checkOut = function () {
var serializedItems = JSON.strigify(items);
//send request to the server...
}
}
var cart = new ShoppingCart();
cart.addItem({ price: 10, type: 'T-shirt' });
cart.addItem({ price: 20, type: 'Pants' });
console.log(cart.getPrice()); //30
One more example of the benefits of the JavaScript scope is the Module Pattern.
In Module Pattern you can simulate privacy using the local functional scope of JavaScript. With this approach you can have both private properties and methods. Here is an example:
var module = (function {
var privateProperty = 42;
function privateMethod() {
console.log('I\'m private');
}
return {
publicMethod: function () {
console.log('I\'m public!');
console.log('I\'ll call a private method!');
privateMethod();
},
publicProperty: 1.68,
getPrivateProperty: function () {
return privateProperty;
},
usePublicProperty: function () {
console.log('I\'ll get a public property...' + this.publicProperty);
}
}
}());
module.privateMethod(); //TypeError
module.publicProperty(); //1.68
module.usePublicProperty(); //I'll get a public property...1.68
module.getPrivateProperty(); //42
module.publicMethod();
/*
* I'm public!
* I'll call a private method!
* I'm private
*/
There's a little strange syntax with the parentless wrapping the anonymous functions but forget it for the moment (it's just executing the function after it's being initialized). The functionality can be saw from the example of usage but the benefits are connected mainly of providing a simple public interface which does not engages you with all implementation details. For more detailed explanation of the pattern you can see the link I've put above.
I hope that with this :-) information I helped you to understand few basic topics of JavaScript.
function Foo() {
this.bar = 0;
this.getBar = function () { return this.bar };
}
When you call the function above with the new keyword - like this...
var foo = new Foo();
... - a few things happen:
1) an object is created
2) the function is executed with the this keyword referencing that object.
3) that object is returned.
foo, then, becomes this object:
{
bar: 0,
getBar: function () { return this.bar; }
};
Why not, then, just do this:
var foo = {
bar: 0,
getBar: function () { return this.bar; }
};
You would, if it's just that one simple object.
But creating an object with a constructor (that's how it's called) gives us a big advantage in creating multiple of the "same" objects.
See, in javascript, all functions are created with a prototype property [an object], and all objects created with that function (by calling it with the new keyword) are linked to that prototype object. This is why it's so cool - you can store all common methods (and properties, if you wanted to) in the prototype object, and save a lot of memory. This is how it works:
function Foo( bar, bob ) {
this.bar = bar;
this.bob = bob;
}
Foo.prototype.calculate = function () {
// 'this' points not to the 'prototype' object
// as you could've expect, but to the objects
// created by calling Foo with the new keyword.
// This is what makes it work.
return this.bar - this.bob;
};
var foo1 = new Foo(9, 5);
var foo2 = new Foo(13, 3);
var result1 = foo1.calculate();
var result2 = foo2.calculate();
console.log(result1); //logs 4
console.log(result2); //logs 10
That's it!
To get closer to OOP in JavaScript, you might want to take a look into a Module design pattern (for instance, described here).
Based on the closure effect, this pattern allows emulating private properties in your objects.
With 'private' properties you can reference them directly by its identifier (i.e., no this keyword as in constructors).
But anyway, closures and design patterns in JS - an advanced topic. So, get familiar with basics (also explained in the book mentioned before).
In javascript this always refers to the owner object of the function. For example, if you define your function foo() in a page, then owner is the javascript object windows; or if you define the foo() on html element <body>, then the owner is the html element body; and likewise if you define the function onclick of element <a>, then the owner is the anchor.
In your case, you are assigning a property bar to the 'owner' object at the begining and trying to return the local variable bar.
Since you never defined any local varialbe bar, it is giving you as bar is undefined.
Ideally your code should have defined the variable as var bar; if you want to return the value zero.
this is like a public access modifier of objects(variables or functions), while var is the private access modifier
Example
var x = {};
x.hello = function(){
var k = 'Hello World';
this.m = 'Hello JavaScript';
}
var t = new x.hello();
console.log(t.k); //undefined
console.log(t.m); //Hello JavaScript
I'm reading the You Don't Know JS books and am on this and Object Prototypes.
I get that to know what this refers to I need to look at the call-site. And the call site is what this will refer to. What I don't get is why this code isn't working as I think it should (I only wrote it to understand this, not for any working problem or anything).
function foo() {
console.log(foo.hasOwnProperty('a')); // 1
console.log(window.hasOwnProperty('a')); // 2
console.log(this.a); // 3
this.a++;
console.log(window.hasOwnProperty('a')); // 4
}
function bar(){
foo.a = 42;
foo();
}
bar();
If you look at the first line in bar which creates an a property for foo and assigns it the value 42. If I comment this line out, then running console.log(foo.hasOwnProperty('a')); gives me false. And if I have it run, then it returns true. But if this is the case, then calling bar is indeed creating an a property for foo, right? This leads to question 3.
I get that at this point window.a does not exist.
Why does this return undefined? this should resolve to foo.a, right? Because the context of this would be in bar, correct? Bar is the call-site. However, this remains undefined regardless of whether foo.a = 42 is commented out or not.
Why does this return true now, after running this.a++? How and why is a global variable being created?
Note: this is just an easy way of thinking about this. In complicated cases (such as when using .bind() or OOP), the following might not be accurate.
this, by default sorta refers to the object that contains the function being called. For example, if I did
var obj = {
fxn: function() {
console.log(this.bar);
},
bar: 3
}
obj.fxn(); // (1)
var fxn = obj.fxn();
fxn(); // (2)
(1) Will print "3" to the console; Because you are, in a way, calling fxn "through" obj, this will point to obj. In other words, because you are calling the copy of fxn that is stored inside of obj, this will point to obj.
(2) Will (assuming bar has not been defined elsewhere) print undefined. That is because fxn isn't being called "through" anything. As a result, it pretends that fxn is being called through window.
Although in your example, foo is being called in bar, bar does not call a version of foo being... well, stored inside itself. bar does not call foo... "through" foo.
Admittedly, that's pretty confusing. Maybe this will clear up some confusion: If you change bar to this:
function bar(){
foo.a = 42;
foo.foo = foo;
foo.foo();
}
it will print 42 instead of undefined. The important part is that the object that foo is being called through will be this. For instance,
function bar(){
var baz = {};
baz.a = 42;
baz.foo = foo;
baz.foo();
}
Will also print 42.
In foo this refers to the parent object - i.e. window.
so this.a and window.a are referring to the same thing.
Because the context of this would be in bar, correct?
Incorrect. For bar to be "this" in foo you would need to apply or call or bind foo passing your desired "this" as context. i.e.
foo.call({});
or
foo.bind({});
Would make "this" and empty object within foo.
Why does this return true now, after running this.a++? How and why is
a global variable being created?
For the same reason - when you do this.a++ you are creating and incrementing a global variable a by one.
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() {
...
}
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