function Person(firstName, lastName, age)
{
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
var family = {};
family.mother = new Person("Susan", "Doyle", 32);
…
Do we have to use "this" here? and why?
function …
{
firstName = firstName;
lastName = lastName;
age = age;
}
I wonder if this question is too simple …
in javascript the this word is a reference to the object of invocation.
So if we have a global function
function () {console.log(this);} // Window
We get the global object or window.
if we have a deeper function in an object
var obj = {f: function (){console.log(this);}};
obj.f(); // Object {f: function} we get the object that wraps the function.
This rule is broken if we use the apply invocation pattern
obj.f.apply(window); // window is now bound to this.
In your example if you were to just call
Person(); // in global scope
you would effectively be assigning
window.firstName = // ...
window.lastName = // ...
window.age = //...
Because the this keyword is bound to the window object when called from global scope
You basically created a Constructor that should be called with the new operator. The new operator wraps your function with one that creates an object and calls your function using the apply method with the object as the this parameter.
var bob = Person("bob"); // bob is undefined but you changed the window object
var sue = new Person("sue"); // sue is an object like you expect.
Examine your code
var family = {}; // make an object
family.mother = new Person("Susan", "Doyle", 32);
because you used new before you function executes js makes a new object for you and uses the apply pattern to that object. This is what happens under the hood
family.mother = {};
Person.apply(family.mother, ["Susan", "Doyle", 32]);
Here this is required to referring the current object's value.
If you don't use the this keyword the local variables get shadowed down by function parameter.
In your Person() function scope - the function parameter get higher priority than the local variable. That means inside your Person() function the by default the firstName is considered as the function parameter even though there is some field by the same name. In this case to reference the field the this keyword is used.
This is the correct way to define an object constructor. you can get reference here
The this Keyword
In JavaScript, the thing called this, is the object that "owns" the JavaScript code.
The value of this, when used in a function, is the object that "owns" the function.
The value of this, when used in an object, is the object itself.
The this keyword in an object constructor does not have a value. It is only a substitute for the new object.
The value of this will become the new object when the constructor is used to create an object.
Note that this is not a variable. It is a keyword. You cannot change the value of this.
Related
It is my understanding that when you change the function prototype of a function to point to a different object the constructor of the new prototype will point to the new object's prototype constructor.
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new:
When the code new Foo(...) is executed, the following things happen:
1) A new object is created, inheriting from Foo.prototype.
2) The constructor function Foo is called with the specified arguments,
and with this bound to the newly created object. new Foo is equivalent
to new Foo(), i.e. if no argument list is specified, Foo is called
without arguments.
3) The object returned by the constructor function becomes the result of
the whole new expression. If the constructor function doesn't
explicitly return an object, the object created in step 1 is used
instead. (Normally constructors don't return a value, but they can
choose to do so if they want to override the normal object creation
process.)
Furthermore, from https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance:
We need to do one more thing before we move on. After adding the last
line, Teacher.prototype's constructor property is now equal to
Person(), because we just set Teacher.prototype to reference an object
that inherits its properties from Person.prototype! Try saving your
code, loading the page in a browser, and entering
Teacher.prototype.constructor into the console to verify.
In my example below customPrototype inherits its properties from Object.prototype as far as I can tell and so once I reassign Person.prototype to that it should change the constructor as well. And logging it I see that the constructor does change!
// Some custom object to inherit
var customPrototype = {
name: "XYZ"
};
// Person has its prototype object pointing to Object.prototype
var Person = function() {
this.name = "Not XYZ";
};
// Prints function() {this.name = "Not XYZ";}
console.log(Person.prototype.constructor);
// Change Person prototype to point to the custom prototype object
Person.prototype = customPrototype;
// Prints function Object() { [native code] }
console.log(Person.prototype.constructor);
var p = new Person();
// Prints Not XYZ
console.log(p.name);
Given the example above I expected the last name to print XYZ because nothing would be overwritten from the customPrototype object.
What am I missing? Why does it still call the Person function when (I think) it should be calling the Object.prototype.constructor?
Prototype.constructor have nothing to do with object initialization. When you want to create an object, you call new Person(), which actually calls the Person function, passes the object as the context (this) into the function and returns that object. Person function is called, no matter what prototype you have for it. And because in this function you have a property name set to Not XYZ, it will have that value. It shadows the prototype property with the same name. If you will delete this property from the object and try to again access name, you will get the prototypes one.
var customPrototype = {
name: "XYZ"
};
var Person = function() {
this.name = "Not XYZ";
};
Person.prototype = customPrototype;
var p = new Person();
console.log(p.name);
delete p.name;
console.log(p.name);
We set the prototype.constructor to keep the precise construction of the object and if we want to have some checkings based on which type of the object is.
Implementing copy logic for the objects of the type Person.
function Person(name) {
this.name = name;
};
Person.prototype.copy = function() {
return new this.constructor(this.name); // Access by `constructor` property, it is not necessary to call directly `Person`
}
const person = new Person('Bob');
console.log(person.name);
const secondPerson = person.copy();
console.log(secondPerson.name);
console.log(person === secondPerson);
The following segment:
var obj = {
name:'Tom',
sayHello:function() {
console.log("hello," + this.name);
}
}
var name = 'Kevin';
var method = obj.sayHello;
method();
will get the output:
hello,undefined
but, if change var name = 'Kevin'; to name = 'Kevin'; The output will be hello,Kevin. Why they are different?
There are two halves to the answer:
When you use var method = obj.sayHello;, you are decoupling the function from obj. When you invoke the a method without giving it an explicit object, (ie, method() instead of obj.sayHello()), JavaScript sets this to the global object, window.
When you define a variable using var name = 'Kevin', you're creating a local variable with function scope. When you define a variable using name = 'Kevin', you're creating a global variable, attached to the global object, window. This is identical to writing window.name = 'Kevin'.
These two things combine to mean that, inside sayHello, this is window and this.name is Kevin.
To solve this, you need to use bind, which returns a copy of your method with its context fixed to the object provided as an argument to bind:
var method = obj.sayHello;
new_method = method.bind(obj);
new_method(); // hello, Tom
sayHello:function() {
console.log("hello," + this.name);
}
this in this function refers to the global object. When you change var name = 'Kevin'; to name = 'Kevin';, name variable is set in the global object. Since, name is set in global and this is global, this.name refers to Kevin and it prints hello,Kevin.
The this keyword can be tricky to get.
If you call obj.sayHello, the this keyword will refer to obj.
When you write method = obj.sayHello that the same thing that writing:
window.method = function() { console.log("hello," + this.name); }
The this keyword will now refer to window.
That's why when you reference a variable having name for its name, you write window.name which can be found by your function.
How you call a function determines the value of this in the method. In your way of calling:
var method = obj.sayHello;
method();
You are losing the obj reference to this inside of your invocation of sayHello() so this is set to the global object or undefined, not set to obj. Thus, the errors you are getting.
When you do this:
var method = obj.sayHello;
All, it does it put a reference to the sayHello function in the method variable. Nowhere is anything to do with obj stored in method. So, when you then call method(), there is no object reference at all so instead of obj.sayHello() which causes this to be set to obj, you're just calling sayHello() all by itself which does not set the value of this to obj.
There are multiple ways to fix it.
1) Helper Function.
var method = function() {obj.sayHello()};
method();
2) Use .bind()
Here .bind() will create a helper function for you.
var method = obj.sayHello.bind(obj);
method();
3) Change sayHello() method
You can change the sayHello() method so it doesn't use the this pointer (which works fine if it is a singleton object, but not if there are multiple instances):
sayHello:function() {
console.log("hello," + obj.name);
}
What's difference of this in the following two cases?
Case 1
var Person = function() { this.name="Allen Kim" }
Person.name; //undefined
Case 2
var Person = function() { this.name="Allen Kim" }
var me = new Person();
me.name // Allen Kim
Just wanted to understand how this scope works on both cases.
Every function in JavaScript is itself an object. So Person.name retrieves the name property from the function itself, which was never set; hence undefined.
You can try this my setting it directly:
Person.name = "John";
Person.name; // "John"
When assigning a property from within the constructor via
this.name = "Allen Kim";
you're setting the property on that instance. When you then instantiate an object with:
var me = new Person();
your constructor will add the name property to me, since this referes to the object being created.
Here are the basic steps taken by the JavaScript engine when calling a constructor function with the new keyword:
Calls the constructor with this set to a new clean object.
Sets the internal [[Prototype]] property of your new object to the constructor's prototype (which, in some implementations, is then available through __proto__).
Sets up the constructor property of your new object as a reference to the constructor function (so instead of the non-standard me.__proto__, you could access the prototype via me.constructor.prototype).
Returns said object.
Note that this is a very basic explanation. There are many other things not included here, but this should give you the gist of it.
On the first case you are looking for a static property on the function itself.
The second case you are returning an instance of an object that has the property by calling a constructor function. Its not really a matter of scope.
var Person = function() { this.name="Allen Kim" }
Person.name; //undefined due to the fact that there is no Person object.
var Person = function() { this.name="Allen Kim" }
var me = new Person();
me.name // Allen Kim --> Person `me`'s name
What is the difference between
function person(first_name, last_name) {
this.first = first_name
this.last = last_name
}
and this:
function person(first_name, last_name) {
var first = first_name
var last = last_name
}
Why only the first one makes person.first & person.last accessible outside the function?
The this keyword within a function is called the invocation context.
1) If you define your function as a member of an object (a method):
myObject.someMethod = function() { this.x = 2; };
then the invocation context, this, is the object to which the method is being added, myObject. So after calling myObject.someMethod(); above, myObject.x is then 2. The member x is undefined until you call the method, unless you defined it before.
2) If you use your function as a constructor with the new keyword, then this refers to the new object that is being created:
function MyX() { this.x = 3; };
var myX = new MyX();
You'll then have property myX.x set to 3.
Note that I called my constructor MyX(), not myX(). You should call yours Person(), not person(). It's just a convention, but it is useful to indicate that a function is meant to be used as a constructor.
3) Finally, if you use this within a function that you call as neither a method nor a constructor, then this refers to the global object (document or, equivalently, window). Note however that if you are using javascript in strict mode (which you should do), this is undefined in such a situation, which means that you basically cannot use this in a function that is not a method or a constructor.
Your specific question refers to case 2), the constructor. this.x = 3 in the constructor just sets property x of the newly created object. After some object myX is created, you can then access and modify x externally as any other object property using myX.x.
when you write constructor function ( using new) - you add properties using this.XXX
then you do :
var p = new Person('s','d');
and then you have access to p.first etc.
in the second example :
youre not creating any properties..
youre only creating private variables.
so you cant access them...
By using this.something you're saying that THIS is an object and something is his property.
By using var, you're saying that it's just a variable and not a property.
More information about variable vs property:
http://javascriptweblog.wordpress.com/2010/08/09/variables-vs-properties-in-javascript/
Because of function scope.
A variable lifetime is between the curly braces of the function. The this keyword allows to access the function properties outside of it.
Definitely take a look at this link: https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope
'var' keyword make a variable scoped. In the last example var first and var last create variable accessible only in the scope of the function. You can see this as a local variable in a constructor.
when in javascript you declare a variable as
var variable
it only exists inside the method where you declared it. If you want a variable to be accessible for everyone (that is, global) it has to be declared without the 'var' part
You do not necessarily have to use this. It'd also work fine if you've got a structure like this:
Person = function(first_name, last_name) {
var first, last;
create(first_name, last_name);
function create(first_name, last_name) {
first = first_name
last = last_name
}
return {
firstName: first,
lastName: last
}
}
Im trying to set up a variable and pass it constructor function essentailly like an anonymous type in c# but javascript doesnt seem to like it...
var aPerson = function Person(){
};
$(document).ready(function(){
Person.prototype.age = 22;
window.alert(aPerson .age);
});
Why cant I do this?
Person is only declared as part of your aPerson variable, but it needs to be defined explicitly (e.g. function Person(){}) before it can be used for prototypical inheritance. You need something more like this:
// Create a Person function object
function Person() {
};
// Modify that function's prototype
Person.prototype.age = 22;
$(document).ready(function() {
// aPerson.__proto__ = Person.prototype
var aPerson = new Person();
// JS checks whether aPerson has age already set, if not, it checks
// aPerson's prototype -- in which case it's given the value 22
alert(aPerson.age);
});
Here's the deal: the property prototype works together with new by copying the prototype reference to the object (you can see what that entails by running console.dir(aPerson) in Chrome console, for example). JavaScript checks the original object itself first, then prototype to see whether a function or property exists. That means you can change the reference prototype age later and see the changes reflected in the original object. Also, you can declare your own age in the original object itself and have that override the prototype.
I'm quite certain you have to reference your function using aPerson rather than Person (externally). Internally, you'd reference it using Person.
Alternatively, you could do this -
function Person() {
}
var aPerson = new Person();
$(function() {
Person.prototype.age = 22;
alert(aPerson.age) //22
});
because aPerson doesn't have an age. You will have to call new for it to work.
var aPerson = function Person(){
};
$(document).ready(function(){
Person.prototype.age = 22;
bPerson = new Person();
window.alert(bPerson.age);
});