I am learning javascript.
Why are functions defined outside of the object?
function Man(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Man.prototype.getName = function () {
return this.firstName + this.lastName;
};
Looks a bit weird to me. It works if I add the function inside the class (removing .protoype etc) but I am being told to define the function outisde the object.
Why?
Looks a bit weird to me.
That's just how setting up the prototypes assigned by constructor functions works. And you're not the only one who finds it awkward, see below. :-) (Update: And see further below for how ES6 makes this so much easier.)
It works if I add the function inside the class (removing .protoype etc) but I am being told to define the function outisde the object.
If you do this:
function Man(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.getName = function () {
return this.firstName + this.lastName;
};
}
...then each Man
object gets its own copy of the function. They don't share, you end up with a new function object for each Man
object. (A smart engine can reuse the underlying function code, but there will be two function objects.) The purpose of prototypes is to create features that can be shared by the objects constructed by the constructor.
The other great thing about prototypes is that the object's connection to the prototype is ongoing, which means you can add features to objects that already exist, by adding to their prototype. Example:
function Man(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Man.prototype.getName = function () {
return this.firstName + " " + this.lastName;
};
var joe = new Man("Joe", "Bloggs");
console.log(joe.getName()); // "Joe Bloggs"
Man.prototype.introduction = function() {
return "Hi there, I'm " + this.getName();
};
console.log(joe.introduction()); // "Hi there, I'm Joe Bloggs"
Note how we added introduction
to the prototype after joe
was created. It doesn't matter, the lookup is dynamic. When you do joe.introduction
, the engine looks for an introduction
property on joe
and, if it doesn't find it, goes looking on the prototype. So adding to the prototype later (indirectly) enhances existing objects.
You're not the only one who finds the syntax awkward. You frequently see people creating "extend
" methods like the one in jQuery, Underscore, Prototype, and so on. The extend method just assigns properties from a source object to a destination object. The simple form of it is:
function extend(target, source) {
var name;
for (name in source) {
target[name] = source[name];
}
}
...although usually you see something with more features (multiple source objects, returning the destination, etc.).
And then you can use it like this:
function Man(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
extend(Man.prototype, {
getName: function () {
return this.firstName + this.lastName;
},
introduction: function() {
return "Hi there, I'm " + this.getName();
}
});
That uses object initializer syntax (sometimes called an "object literal"), passes it into extend
, and extend
puts the properties on Man.prototype
.
You also see things like my Lineage
script which simplify that syntax further and handle making a few other things (like calling a parent prototype's version of a function) simpler.
As of ES6, which is very nearly finalized and is making its way into browsers (you can also transpile), this gets a lot simpler:
class Man {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getName() {
return this.firstName + " " + this.lastName;
}
introduction() {
return "Hi there, I'm " + this.getName();
}
}
var joe = new Man("Joe", "Bloggs");
console.log(joe.getName()); // "Joe Bloggs"
console.log(joe.introduction()); // "Hi there, I'm Joe Bloggs"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With