How does "this" keyword work in the particular way? - javascript

I'm trying to learn JavaScript, but got stuck with a problem (more with misunderstanding "this" keyword) that doesn't give me move on.
I've watched a lot of content about it and barely understood it, but still have some troubles.
I have some code:
function Person (name, age) {
this.name = name;
this.age = age;
this.changeName = function (name) {
this.name = name;
}
}
What do we use "this" here for?
As I understood we use "this" to create variable inside function constructor and give it value of our "name" parameter that we could refer to it. Am I right?
Then I have this code:
var p1 = new Person ("John", 30);
p1.changeName ("Jane");
console.log(p1.name);
As I sorted out here, we call method that overwrites our variable that we created to refer to. But it doesn't change actual parameter. So if it's right why do we use it? Doesn't it matter to have actual "name" parameter changed?
The whole code is from teaching app!

So if it's right why do we use it? Doesn't it matter to have actual "name" parameter changed?
No, there's no need to do that in this example. changeName changes the property on the object that was created by new Person.
It's true that that example code is a bit odd, because it creates the changeName function in the constructor but doesn't do the kinds of things you'd normally do when you create the function in the constructor. I'd expect that code to either be this, which puts the changeName on the prototype:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.changeName = function(name) {
this.name = name;
};
(or the class equivalent) or this:
function Person(name, age) {
this.getName = function() {
return name;
};
this.changeName = function(newName) {
name = newName;
};
this.getAge = function() {
return age;
};
}
That code does update the parameter (which has no effect at all on the code calling Person). It doesn't create name and age properties at all; instead, it just makes their values accessible via getName and getAge. There's also a function to change name (changeName); but there's no function to change age. People write code like that so that age cannot be changed from outside code created within the Person constructor.

I guess you may misunderstand which parameter you actually change, so I rewrite it like so, holp this helps.
function Person (argument_name, argument_age) {
this.name = argument_name;
this.age = argument_age;
this.changeName = function (argument_change_name) {
this.name = argument_change_name;
}
}
let p1 = new Person ("John", 30);
p1.changeName ("Jane");
console.log(p1);

The this keyword is used to create and assign values to variables in the class. It is again used to create functions, either getters or setters. So in your code this.changeName is a function that when passed a value will change the name of the person.
eg.
var a = 5; // a is an integer
var b = "Han"; //b is a string
var c = function(name){
//code here
} // then c is also a function;

Related

A JavaScript inheritance example

For example, I have a person constructor as follows:
function Person(name) {
var username = name;
return {
getName: function() {return username;},
setName: function(name) {username=name;}
}
}
Then I want to create another Employee constructor which would inherit from the Person constructor and has a getId method that returns an auto-incremented id value for every object created out of the Employee constructor. For example,
var employee1 = new Employee('foo');
employee1.getName() // will output foo
employee1.getId() // will output 1
var employee2 = new Employee('qoo');
employee2.getName() // will output qoo
employee2.getId() // will output 2
The problem is I'm a little bit confused about how to create an id variable on Employee constructor that it only gets called once and then each object will get a fixed auto-incremented value. How should I set up the Employee constructor and the inheritance?
Given your Person constructor, you do not want to use prototypal inheritance but parasitic one.
The Employee constructor will be quite similar in the regard of creating local variables and defining local functions, only that the id will be initialized by incrementing a static counter instead of a paramter:
Employee.counter = 0;
function Employee(name) {
var that = Person(name);
var id = Employee.counter++;
that.getId = function() { return id; };
return that;
}

javascript: explanation needed for this piece of code

Who can explain me this code (alert "Hi! My name is Mark" appears):
function Person(name) {
var self = this;
this.name = name;
function person(){
alert("Hi! My name is "+self.name);
}
return {person:person};
}
new Person("Mark").person();
and why I don't see alert if return {person:person}; is removed? What person:person is here?
Also, why this.name (not self.name) is undefined in function person(){}?
The main problem is that you should not return {person:person}, but you should not specify a return or "return this;".
new Person("Mark") will create an instance of Person, but the function Person returns the {person:person}. Inside {person:person} the right one(value) is the method.
var x = new Person("Mark") will return {person: function person(){alert("Hi...")}.
x.person() will show the alert.
Niels' answer is correct, and to answer the rest of your question, this.name doesn't work inside the child function because name belongs to the parent function so you have to declare an instance of that parent scope (in your case self) to be able to access the properties of the parent.
This code is very tricky:
function Person(name) {
//'P' makes us think about this function as a constructor
var self = this;
// Closure, when the person function is executed
//"this" is not a Person, is another object, but "self" will be accesible
// by the function person
this.name = name;
// this is an internal function, it does not exist out of Person
function person(){
alert("Hi! My name is "+self.name);
}
return {person:person};
//This should not be here if the Person function were a proper constructor,
//it returns an object which only attribute is the function person
}
new Person("Mark").person();
// as Person returns an object (not a Person object) with the person attribute,
// you can call that attribute
The equivalent but clearer code to this one is:
var p={
person: function () {
var self={name: "Mark"};
(function(){
alert("Hi! My name is "+ self.name);
})();
}
};
p.person();

How to delete a function from constructor?

How to delete a function from constructor?
If there is a function called greet in the Person constructor, how do I remove the function?
function Person(name)
{
this.name = name;
this.greet = function greet()
{
alert("Hello, " + this.name + ".");
};
}
I want the result to be:
function Person(name)
{
this.name = name;
}
delete this.greet
or
var personInstance = new Person();
delete personInstance.greet // to remove it from the instance from the outside
or
delete Person.prototype.greet // if doing prototypes and inheritance
delete is a keyword that your very rarely see but I assure you, it exists :P
You cannot change the source of a function. If you want to change that function's behaviour, you have to options:
Override the function with your own. This is easy if the function is standalone. Then you can really just define
function Person(name)
{
this.name = name;
}
after the original function was defined. But if prototypes and inheritance are involved, it can get tricky to get a reference to the original prototype (because of the way how function declarations are evaluated).
Ceate a wrapper function which creates and instance and removes the properties you don't want:
function PersonWrapper(name) {
var p = new Person(name);
delete p.greet;
return p;
}
This approach is also limited since you can only change what is accessible from the outside. In the example you provided it would be sufficient though.

Most optimized way to create JS Object

I'm looking for the most optimized way to have an object in JS; since JS allows you to do something in multiple ways I want to know which is considered to be "best practice".
A conceptual use of the object would be this:
var John = new Person('John');
var Foo = new Person('Foo');
console.log(John.getName()); //Return 'John'
console.log(Foo.getName()); //Return 'Foo'
console.log(John.name); //undefined
console.log(Foo.name); //undefined
I have some examples here:
Example #1:
var Person = function (name) {
this.getName = function () { return name; }
}
Here I actually have no properties; "name" cannot be changed or be read by public and getName method can be accessed public and invoke with local name variable. This actually meets my needs.
Example #2:
function Person (name) {
this.getName = function () { return name; }
}
This has same behaviour as example #1. I'm just not sure about the difference between var method = function () {}; and function method() {}; from a functional and performance perspective.
Example #3:
var Person = function (name) {
this.name = name;
Person.prototype.getName = function () { return this.name; }
}
Here I have name property which can be read/write by public and I also have a prototype getName method that can be accessed public.
Example #4:
var Person = function (name) {
this.name = name;
if (!Person._prototyped) {
Person.prototype.getName = function () { return this.name; }
Person._prototyped = true;
}
}
Here I have what I had in example #3 with the difference that I make sure that prototype methods are set only once and only when required.
So the end question is, which of those you will suggest me to follow or if any of them then which way is the best practice?
For what you want, the best way is probably this:
/**
* #constructor
*/
function Person(name) {
this.getName = function() {
return name;
};
}
Why is this? Well, first of all, encapsulation. If possible, you generally want to put the function in the prototype, like so:
/**
* #constructor
*/
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
};
However! In this case, it appears you don't want Person.name to be accessible. For that reason, you need to use closures.
As for this method:
var Person = function (name) {
this.name = name;
Person.prototype.getName = function () { return this.name; }
}
That's not good. You publicly expose this.name, so it offers no advantage over the previous prototype method, but you continually overwrite Person.prototype.getName with the same function. There's no point in doing that; this will be the appropriate object every time. What's more, Person.prototype.getName won't be accessible until the first Person object is instantiated so there's not much point in making it "public" in the first place. Your fourth example is basically identical, with more cruft making it harder to understand, but it still has all the disadvantages.
So, in this case, go with the first version; when possible, though, set methods on prototype so they can be called outside of an instance.
Finally, I would recommend using:
function Person() {
}
over
var Person = function() {
}
because 1) The second example is missing a semicolon, 2) the var implies that the constructor is variable which it should not be, and 3) I don't believe JDoc allows #constructor to be applied to it, causing a warning in Closure Compiler at least1.
1 Okay, not so important. But still...
In example 3 and 4 it should be:
var Person = function (name) {
this.name = name;
};
Person.prototype.getName = function () { return this.name; }
And:
var Person = function (name) {
this.name = name;
};
if (!Person._prototyped) {
Person.prototype.getName = function () { return this.name; }
Person._prototyped = true;
}
As you don't need to mess with the prototype each time you call the constructor.
Not sure which is fastest (as they are all valid for your purposes), which is what your asking, but I wouldn't worry as this seems like micro-optimizing. If you must know then you can use a site like http://jsperf.com/
The fastest way I can imagine would be :
function Person(name) {
this.getName = function() {
return name;
};
}
As minitech said. The reason is as follows:
Each time the js engine has to go "up" the prototype chain it takes away a fraction of a ms (or fraction of a sec on IE :) ), and as declaring variables can take up time (also negligible) you avoid doing that too. Hope that helps
Works well on node.js. AFAIK, arguments are mutable. Closures will remember values. Hence this will work. I guess this solves it all.
var Person = function(Name) {
this.getName = function(){return Name;}
this.setName = function(newName) { Name = newName; }
},
me = new Person('John');
console.log(me.getName());
me.setName('Peter');
console.log(me.getName());

How to find the function name of namespaced constructors in javascript?

For example, compare these two:
function Person(name) {
this.name = name;
}
var john = new Person('John');
console.log(john.constructor);
// outputs: Person(name)
var MyJSLib = {
Person : function (name) {
this.name = name;
}
}
var john2 = new MyJSLib.Person('John');
console.log(john2.constructor);
// outputs: function()
The first form is useful for debugging at runtime. The 2nd form requires some extra steps to figure out what kind of object you have.
I know that I could write a descriptive toString function or call the toSource method on the constructor to get some more information, but I want the simplest way possible.
Is there a way to do this? Suggestions?
Well that happens because you are using an anonymous function.
You can specify names of anonymous functions (yes, it sounds odd), you could:
var MyJSLib = {
Person : function Person (name) {
this.name = name;
}
}
var john2 = new MyJSLib.Person('John');
console.log(john2.constructor);
Anonymous functions can be named but those names are only visible
within the functions themselves, and since you use the new operator, the constructor property will be set, and you will be able to see the name.
You could also compare the constructor reference using or not a name for the function:
console.log(john2.constructor === MyJSLib.Person); // true
If you want to check whether an object is instance of a specific class then simply use "instanceof" keyword to check that. If you explicitly want a name for the constructor(which I really cannot see a point) you may try the code below
var MyJSLib = {
Person : function Person(name) {
this.name = name;
}
}
what you want is the name of the holder in the namespace so.
function getName(namespace, obj) {
for name in namespace:
if (namespace[name] == obj) return name;
}
console.log(getNameOf(MyJSLib, john2.constructor));

Categories