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();
Related
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;
Is it possible to use the statement as shown below to define a method without the use of prototype?
Person.sayHello = function () {...}
On this example
var Person = function (firstName) {
this.firstName = firstName;
};
Person.prototype.sayHello = function() {
console.log("Hello, I'm " + this.firstName);
};
var person1 = new Person("Alice");
var person2 = new Person("Bob");
In short, no.
Person.sayHello = function () {...};
This line will add a function called "sayHello" to the Person class itself rather than to instances of the Person class. So, it can only be invoked by
Person.sayHello();
rather than by
var matt = new Person('Matt');
matt.sayHello();
// sayHello is not defined on matt
If you are familiar with Java or C#, adding a method to Person in this way is like creating a static method.
However, we can add a method to instances without adding a method to the prototype.
Method 1: Create the "sayHello" function in the constructor of Person
var Person = function (firstName) {
this.firstName = firstName;
this.sayHello = sayHello() {...};
};
This method has the disadvantage that a new function is created for every instance of Person. That is,
var frank = new Person('Frank');
var matt = new Person('Matt');
// frank.sayHello != matt.sayHello;
Thus, this method can be hard on memory. However, it does allow for encapsulation (e.g. private state) via closures. In the following sample, it is impossible to modify the "count" variable outside of the Person class without calling the "sayHello" function.
var Person = function (firstName) {
this.firstName = firstName;
this.sayHello = sayHello() {
count++;
console.log("Hello has been said " + count + "times".
};
var count = 0;
};
Method 2: Create the "sayHello" function outside the constructor of Person and assign it within the constructor of Person
var Person = function (firstName) {
this.firstName = firstName;
this.sayHello = sayHello;
};
function sayHello() {...}
This method has the advantage of lower memory usage; there is only one instance of the sayHello function, and it is shared across instances of Person. That is,
var frank = new Person('Frank');
var matt = new Person('Matt');
// frank.sayHello == matt.sayHello;
This makes it similar to the prototype method. However, the assignment of the function to each instance still consumes more memory than the prototype method where the function is only assigned to the prototype object.
However, like the prototype method, this method does not allow for private state. All state must be accessed through public state exposed via the this keyword.
Update: Clarification of the difference in memory usage between method 1 and method 2.
Method 1 is like this:
var function1 = function() { console.log('Hello'); };
var function2 = function() { console.log('Hello'); };
The functions have the same behavior, but are not equal. JavaScript doesn't know they are functionally similar, so it creates two functions in memory to represent them.
Method 2 is like this:
var sayHello = function() { console.log('Hello'); };
var function1 = sayHello;
var function2 = sayHello;
Now function1 and function2 are actually the same function because they both simply hold a reference to sayHello.
Update: Example usage of a module pattern to avoid adding "sayHello" to the global scope in method 2.
This module defines the Person class in a module defined by an anonymous closure (a self executing function) and exports it to the global scope. Because "sayHello" is defined in the closure of the module and is not exported, it is not added to the global scope.
var Person = (function () {
function Person(firstName) {
this.firstName = firstName;
this.sayHello = sayHello;
};
function sayHello() {...}
return Person;
}());
Yes, you can. If you come from traditional OO background, it might help to think about this as effectively behaving like a public static property on a class.
As jsdeveloper said in the above comment. Functions are just objects that can be executed. You can add properties to them just like any other object. This technique is actually used in practice for patterns like memoization or currying.
In your case sayHello can accessed anywhere the Person function can be accessed. It's not really related to inheritance/prototype since it doesn't have to do with resolving properties by traversing the prototype chain, but it is another way to make data accessible.
I'm sure it varies based on the developer, but I often put pure functions which don't reference this as static methods as you have done since they are easier to test and make the intention clear to other developers
It would be weird, but if you really need to do it that way, you can assign the function to its own prototype once, then add all of the functions to the main function.
var Person = function (firstName) {
this.firstName = firstName;
};
Person.prototype = Person;
Person.sayHello = function() {
console.log("Hello, I'm " + this.firstName);
};
Yes you can but the sayhello function will not be able to access any of the object properties (ie this.myvar) and you can only call it like a static method:
Person.sayhello()
(and not mypersonobject.sayhello).
When you extend the prototype, the sayhello function is available to all Person objects created using the 'new' keyword in the usual fashion.
https://jsfiddle.net/jsheridan390/kL7arrqs/
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;
}
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.
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));