Reputation: 1070
I'm working through CodeAcademy JS excercises and have a question about this example:
//Animal class
function Animal(name) {
this.name = name;
}
//Attach sayName method to Animal class
Animal.prototype.sayName = function() {
console.log("Hi my name is " + this.name);
};
//create an animal object instance
var dog = new Animal('Barker');
//invoke a method attached to the prototype from the object instance
dog.sayName();
My understanding of this code is:
Animal()
- a function constructorsayName()
method attached to it in the line: Animal.prototype.sayName = function()
sayName()
was attached to the class prototype
, the method is now available to any objects created from the Animal
class through use of the new Animal()
function constructorIs this a correct understanding of what is happening with this code?
Also, I'm trying to understand how this
points to the Animal object in this.name
:
Animal.prototype.sayName = function() {
console.log("Hi my name is " + this.name);
};
Doesn't Animal.prototype
point to an actual object: the prototype
object of this Animal
object instance? If so, shouldn't this
in this.name
point to Animal.prototype
, since sayName()
is actually being invoked from Animal.prototype
?
My understanding of the context for this
is that this
always points to the object that invokes the function. However, in this case, when dog.sayName()
is invoked, this
points to Animal
, which is how this.name
equals 'Barker'
when it is logged to the console.
I'm guessing that either I am misunderstanding that Animal.prototype points to a prototype object, or that JS is doing something "behind the scenes" to associate dog.sayName()
to this
in the context of attaching a method to the prototype
.
Multiple questions here in this little example, but getting a grasp on exactly what is happening here will really help my understanding of these fundamental concepts.
Upvotes: 2
Views: 961
Reputation:
this
has two distinct characteristics in Javascript that cause a lot of confusion:
Lexical scope
var i = 0;
const inc = () => i + 1;
const inc2 = x => {
var i = x;
return inc();
};
inc2(100); // 1
Dynamic scope
var o = {
i: 0,
inc: function () { return this.i + 1 }
};
var p = {
i: 100,
inc2: o.inc
};
p.inc2(); // 101
this
is dynamically scoped, because it's set through the invocation context.
Implicit parameter
Instead of passing this
explicitly as a formal parameter to methods, it's treated implicitly. Hence you need to use call
/apply
to set different values (namely objects) for this
:
// Note that s and t are implicitly converted to objects
const split = (o, x) => o.split(x);
let s = "1,2,3", t = "4,5,6";
// objects are passed explicitly as normal arguments
split(s, ","); // ["1", "2", "3"]
split(t, ","); // ["4", "5", "6"]
// objects (or this) are provided implicitly
s.split(","); // ["1", "2", "3"]
s.split.call(t, ",") // ["4", "5", "6"]
Imagine this
as the receiving object of a method, which must be passed as the first parameter.
Upvotes: 1
Reputation: 60577
[points 1-3]
Is this a correct understanding of what is happening with this code?
Yes, sounds like you understand it.
Doesn't Animal.prototype point to an actual object: the
prototype
object of thisAnimal
object instance?
Yes, the prototype
object is an Object
instance.
If so, shouldn't
this
inthis.name
point toAnimal.prototype
, sincesayName()
is actually being invoked fromAnimal.prototype
?
No, because you called it as a method of dog
.
dog.sayName();
If you called it like this, then yes, this
would have referenced Animal.protoype
.
Animal.protoype.sayName();
But that wouldn't be very useful.
My understanding of the context for
this
is thatthis
always points to the object that invokes the function.
Not quite. For the most part this
refers to the object the method was called on, not the object it is a property of. A method can actually be a property of multiple objects, so this
dynamically points to the object it was called as a method of.
Of course, this
can refer to other things in other contexts, such as when not called as a method, or in a bound function using .bind
.
Upvotes: 2
Reputation: 288490
You misunderstood this
. The value of this
is not set when you create the function, it's an additional argument. Each time you call a function, the this
value can change.
In case of methods, the this
value is set to the base object. For example,
dog.sayName(); // `this` is `dog`
({sayName: dog.sayName}).sayName(); // `this` is this new object
(0,dog.sayName)(); // `this` is undefined or the global object
Upvotes: 1