this is #33 from John Resig`s Learning Advanced JavaScript. http://ejohn.org/apps/learn/#33 Would appreciate as much help as you can provide on this.
1) technically speaking, is ninja.changeName("Bob") "calling" the function Ninja, or does it go immediately to this.changeName(name);
2) Once ninja.changeName("Bob") is invoked, what is the order in which the processing events take place inside function Ninja(name)?
3) what exactly is the purpose/function of this.changeName ( name);
function Ninja(name){
this.changeName = function(name){
this.name = name;
};
this.changeName( name );
}
var ninja = new Ninja("John");
assert( ninja.name == "John", "The name has been set on initialization" );
ninja.changeName("Bob");
assert( ninja.name == "Bob", "The name was successfully changed." );
1) technically speaking, is
ninja.changeName("Bob") "calling" the
function Ninja, or does it go
immediately to this.changeName(name);
The function Ninja can be only called with the syntax Ninja(..). The syntax new Ninja(...) doesn't exactly call the function, it uses it as a constructor for a new object. And the syntax ninja.changeName("Bob") calls the anonymous function attached to the changeName property of the ninja object by its Ninja constructor. ninja.changeName("Bob") has very few things to do with the Ninja function, "technically speaking". Once the object ninja has been created, there is no relation at all between ninja.changeName and Ninja.
Returning to your question: neither. It doesn't "call" the function Ninja, and it doesn't go to this.changeName(name). It simply calls the function ninja.changeName, which is a regular, anonymous function, referenced by a property of our object ninja.
2) Once ninja.changeName("Bob") is
invoked, what is the order in which
the processing events take place
inside function Ninja(name)?
As written above, there's no relation between the two. Executing ninja.changeName("Bob") does a call on the anonymous function referenced by ninja.changeName. The association between ninja.changeName and the anonymous function function(name) { this.name=name; } has been set by the constructor Ninja, but that's the only relation between them.
3) what exactly is the
purpose/function of this.changeName (
name);
The function changeName is called in the constructor to show you that a method can be called inside the constructor. You can create setters for an object, then use these setters in the constructor to initialize the object's properties. The example is didactic ; in the real world, setters can be quite complicated, and you have to use them to initialize the object. And besides, what would be the point of creating a setter if don't use it, like in :
function Ninja(constructorArg) {
this.changeName = function(setterArg){
this.name = setterArg;
};
this.name = constructorArg; // I'm not using the setter I've just written
}
1) It is calling the method on the function.
2) It simply updates its own name property via the setter.
3) It is to use a setter to change a property.
1) technically speaking, is ninja.changeName("Bob") "calling" the function Ninja, or does it go immediately to this.changeName(name);
It calls the anonymous function that is assigned to the changeName property of the instance of Ninja that is created with var ninja = new Ninja("John");.
2) Once ninja.changeName("Bob") is invoked, what is the order in which the processing events take place inside function Ninja(name)?
The single statement in that function is run
3) what exactly is the purpose/function of this.changeName ( name);
It takes one argument, and assigns the value of that argument to the name property of the instance of Ninja on which the method is called.
this is very good question)
in JS functions are objects, so by calling ninja.changeName("Bob") you go straight to ninja's method .changeName()
if ninja.changeName was called no actions outside this method will be fired
this.changeName ( name); - is constructor actions, they are applied to ninja object on creation only (to extend the newly created object with property name)
take a look at this great book on OOP in JS
Related
I have read over some rules to determine what the value of this is in different scenarios in Javascript. All was well till the example below threw me off.
function Person(name){
this.name = name; //this is the object when function used as constructor (as expected)
this.changeName = someFunction(); // produces error
function someFunction(){
this.nickName = this.name+"by"; //this is now the global object and not the instance, thus the name property does not exist.
}
}
var a = new Person ('bob'); //error due to the function in changeName property.
From what I understood, the this variable takes up the value of the invoking object when called through dot notation or takes up the value of the newly constructed function when used with the new key word.
Can someone explain why the this statement in the function above is the global objet and not the newly instantiated object?
Can someone explain why the this statement in the function above is the global objet and not the newly instantiated object?
Because when you call a(n unbound) function as func(), this will refer to the global object (or undefined if the function is in strict mode).
Every function (except arrow functions) has its own this value. So the fact that you are calling Person as new Person() and that this inside Person refers to a new object, doesn't have any impact on the this value in someFunction. It only matters how you can someFunction.
You could call someFunction and explicitly set its this value via .call:
this.changeName = someFunction.call(this);
See also: How to access the correct `this` inside a callback?
The this within someFunction() will reference a global object, because it's inside a function call. See a fuller, much more complete explanation at How does "this" keyword work within a function?
If you wish to solve the issue, alias this inside the parent.
function Person(name){
var self = this; // Store a reference to the current instance
self.name = name;
self.changeName = someFunction(); // Odd that you'd capture the return value of a setter, ...
function someFunction(){
self.nickName = self.name+"by"; //self references the instance, creating the property.
}
}
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:
JS creates a new Animal object instance that var dog points to as a result of the use of the new keyword before the call to function Animal() - a function constructor
The prototype of the var dog object has the sayName() method attached to it in the line: Animal.prototype.sayName = function()
Because 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 constructor
Is 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.
[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 this Animal object instance?
Yes, the prototype object is an Object instance.
If so, shouldn't this in this.name point to Animal.prototype, since sayName() is actually being invoked from Animal.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 that this 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.
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
this has two distinct characteristics in Javascript that cause a lot of confusion:
it's the only dynamically scoped built-in feature of the language
it's treated as an implicit parameter
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.
First post. New to programming.
In Javascript, when I declare a new variable and also set this newly declared variable to store a function, is that function immediately executed when the code runs (execution context)?
For instance,
function Person() {
console.log(this);
this.firstname = 'John';
this.lastname = 'Doe';
}
var john = new Person();
Is the variable john being declared at the same time the function "Person" is being executed on that same line?
What you copy/paste is an object creation. It means john is a new Person object. Person being the class of the object. The this keywork in your Person function is related to the instance of the newly created object. Don't be abused by the function keyword, which is a confusing (because of historical reason) JS keyword. Person function can be seen as an object constructor.
EDIT : removed the off topic remark (really too much off topic)
var john = new Person();
Variable john is created.
RHS is executed.
2.1. new operator calls the contructor of the Person. Every function implictly has a constructor(). This results in Object creation.
Result of RHS evaluation is returned (which is an object in this case).
Result is assigned to john or in other words, now john (a reference variable) will refer to the object which was created as a result of new operator executed on Person().
If you put () or (optionalArgumentsHere) (some functions take arguments, some don't) after a function it means it is a function call, and it will be executed. If you want to assign the function itself to a variable, you need to omit the (). It is possible because functions are objects in JavaScript (which is not true in every language).
So what happens here is that you declare a variable (you actually declare it earlier because of hoisting, as explained by Pablo), you execute new Person() and assign the result to the variable.
If you called some function like
function fun() {
return 5;
}
var x = fun();
You would be assigning the return value of the function to the variable. But your case is special, because you use new. That means Person is a constructor, and it is used to create a new object of type Person. Inside that constructor, you use the this keyword to attach properties to the newly created object. The new Person() call returns the object, even though return is not called explicitly.
In Javascript, variable definitions are "hoisted". It means that the code that you posted and the following one...
var john;
function Person() {
console.log(this);
this.firstname = 'John';
this.lastname = 'Doe';
}
john = new Person();
... are identical, because the compiler will hoist the variable declaration to the beginning of the current context. So, the answer is no, the variable is declared, then the function is executed as a constructor, and then the new creadted object is assigned to that variable.
You can find more information here
Most of us know that JavaScript has no sense of "private" properties, but that behavior can be emulated through the use of closures:
var Car = function () {
var name = 'Tesla';
var wheelCount = 4;
this.getName = function () {
return name;
};
this.getWheelCount = function () {
return wheelCount;
};
this.setName = function (newName) {
name = newName;
};
this.setWheelCount = function (newCount) {
wheelCount = newCount;
};
};
var myCar = new Car();
console.log(myCar.name); // undefined
That all makes sense to us that know about how JavaScript closures work. However, the following will work:
myCar.name = 'Corvette';
console.log(myCar.name); // 'Corvette'
But then if you call the function from the prototype, the enclosed variable is still used
console.log(myCar.getName()); // 'Tesla'
When you call myCar.name, you're adding a new property to the object. Is it just the entire point of using this when declaring the getName (etc) functions inside the Car definition to make the differentiation between the enclosed name inside the Car declaration versus the myCar.name?
I have a feeling that I know the answer to this, but I would like to be certain. Plus, I think this would be something invaluable to other people getting an advanced grasp on how JavaScript enclosures work.
Is it just the entire point of using this when declaring the getName (etc) functions inside the Car definition to make the differentiation between the enclosed name inside the Car declaration versus the myCar.name?
Yes.
this (or myCar) is the object, on which you put the properties that you want to have it (in this case all those methods). If you want to use properties, you must use a property accessor.
var name is just a local variable in the constructor function, which is accessed by closure from the object's methods.
Or, to answer your title question:
If a variable is enclosed, and an instance sets a property with the same name, where does the property go?
The property goes on the object. It doesn't interfere at all with the variable, which is located in the scope of the Car constructor invocation.
In your example car function is a constructor function. When a constructor function is called with new operator, a new object is created and "this" gets bound to that new object. And "this" is returned from the function even if there is no return statement (unlike non-constructor functions that returns undefined if nothing is returned)
So When you called new Car() a new object got created and as "this" was bounded to this new object, the new object got 4 functions that you defined in Car function (getName, getWheelCount, setName, setWheelCount)
The name variable defined in Car function is not bounded to "this", it is bounded to Car's function scope. When car function returned "this", because of closure getName() still has access to function's name variable.
Now when you tried myCar.name, as the new object that was created does not have any variable called name, it printed undefined.
On doing myCar.name = 'Corvette', as no property named name was found in myCar,new property was created with name "name" and value "Corvette" (javascript creates a new property if it is not already existing in case of write operations, for read operations prototype chain is followed)
But surprisingly myCar.getName() still prints "Tesla" and not Corvette, because though the variable names are same they are in diffrent scope.The one that is referred by getName was part of Car function scope and is bounded to getName via Closure, but the name ("corvette") that you added belongs to new object that you created.
The purpose of "this" is to add the functions/variables defined inside constructor function to the object that you are going to create through that constructor function.
Hope it helps.
I'm trying to learn JS from online tutorial - http://ejohn.org/apps/learn/#33 , you can test JS code there. I'm trying to understand nesting functions as methods inside of other functions and what "this" keyword is referencing then. Why if I put on above site code from below - it doesn't work? Could someone explain that aspect of JS?
function Ninja(name){
this.name = name;
this.changeName = function(newname) {
this.name = newname;
this.anotherFunction = function(newname2) {
this.name2 = newname2;
}
}
}
var ninja = new Ninja("John");
assert( ninja.name == "John", "The name has been set on initialization" );
// ninja.anotherFunction("Luken");
// ninja.changeName.anotherFunction("Luken");
// Why both above functions doesn't work?
assert(ninja.name2, "It works?");
ninja.changeName("Bob");
assert( ninja.name == "Bob", "The name was successfully changed." );
The value of this is determined at the time the function is invoked, not the time when it is defined. So in your code, you have to different values of this: When ninja.changeName() is called, you don't specify a value for this, so it's either undefined or whatever it might be right now.
The new operator, on the other hand, does set this before it called the function Ninja.
What you need to do is "save" the value of this inside of Ninja so the inner functions continue to use that (instead of whatever random value might be in this at the time they are called). Doing this is more simple than it sounds:
function Ninja(name){
this.name = name;
var self = this; // Create a hidden reference to "this" that is only visible in
// any functions defined before we return
self.changeName = function(newname) {
self.name = newname;
self.anotherFunction = function(newname2) {
self.name2 = newname2;
}
}
}
This works because JavaScript keeps a copy of the context (= all reachable variables) around when you define a function.
It's fairly simple:
function Ninja(name)
{//this points to Ninja object inside constructor scope
this.name = name;
this.changeName = function(newname)
{//method of Ninja, this points to context object, ie Ninja
this.name = newname;//accesses the name property of Ninja
this.anotherFunction = function(newname2)
{//defines new method for this ==> Ninja object
this.name2 = newname2;//context object is Ninja
};
};
}
var foo = new Ninja('foobar');
foo.name;//foobar
foo.changeName;//function, is defined in constructor
typeof foo.anotherFunction//undefined because it's assigned when the changeName method is called!
foo.changeName('Me');
foo.name;//Me
foo.anotherFunction('You');//works: changeName was called, and assigned anotherFunction to foo (instance of Ninja)
foo.name2;//You
What happened: simple, by invoking the changeName method, anotherFunction was defined and assigned to this. At that time this referenced the Ninja object, so the method was assigned to the instance of Ninja from which the changeName method was invoked. Prior to calling the changeName method, the anotherFunction method simply didn't exist.
Though this might seem useless or stupid, it does make sense. What you need to remember is that functions/methods are, in essence stand-alone objects. In this code, they just happen to be defined as properties/methods, but they needn't be used as such. Going back to the code above:
foo.name;//Me
bar = {};//some object
foo.changeName.apply(bar,['You']);
foo.name;//Me, nothing has changed, the changeName method was applied to the bar object
bar.name;//You, in the apply call, this pointed to bar, not foo
typeof bar.anotherFunction;//function
//You could even create the anotherFunction globally:
// JUST TO SHOW YOU CAN, THIS IS DANGEROUS
// ONLY USE THIS IF YOU KNOW WHAT THE POSSIBLE CONSEQUESES ARE!
foo.changeName.call();//in global scope
typeof antoherFunction;//function ==> this function is now globally available
The changeName method can be applied to any object, adding a new method, changeing/adding certain properties to that particular instance.