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));
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;
I'm not sure if the Title actually made any sense but however I'm trying to set a functions prototype to "sub classes" prototype.
For coming example;
What I try to do is : I have a user and paidUser . paidUser is subclass ofuser
User Factory function :
function userCreator(name, score) {
this.name = name;
this.score = score;
}
userCreator.prototype.sayName = function(){console.log("hi");}
userCreator.prototype.increment = function(){this.score++;}
And I can create a new user with new keyword. so far so good.
const user1 = new userCreator("Phil", 5);
Now , coming to Subclassing . (accountBalance is just a silly property special for paidUser for my example)
function paidUserCreator(paidName, paidScore, accountBalance){
userCreator.call(this, paidName, paidScore);
this.accountBalance = accountBalance;
}
now I want to set prototype of my userCreator as the prototype of paidUserCreator Factory Function
The following line works perfectly, but I don't understand it quite. Object.create function is supposed to created an empty object and that empty objects __proto__ must be the given parameter.
paidUserCreator.prototype =Object.create(userCreator.prototype);
paidUserCreator.prototype.increaseBalance = function(){
this.accountBalance++;
}
Another point what I don't understand is :
Why the following line doesn't work ?
Object.setPrototypeOf(paidUserCreator, userCreator.prototype);
For completion :
const paidUser1 = new paidUserCreator("Katarina", 4, 12);
PS: Yes I know the Class keyword is much cleaner and nicer to read but I want to learn how to do it in this way.
Starting with the last question:
Why the following line doesn't work ?
Object.setPrototypeOf(paidUserCreator, userCreator.prototype);
It will, but you need to set the prototype of paidUserCreator.prototype not the function paidUserCreator so that when an instance looks for something on the paidUserCreator.prototype and doesn't find it, it will look to userCreator.prototype.
function userCreator(name, score) {
this.name = name;
}
userCreator.prototype.sayName = function() {
console.log("hi");
}
function paidUserCreator(paidName, paidScore, accountBalance) {
userCreator.call(this, paidName, paidScore);
}
Object.setPrototypeOf(paidUserCreator.prototype, userCreator.prototype);
let p = new paidUserCreator("Mark", 98, 200.5)
p.sayName()
paidUserCreator.prototype = Object.create(userCreator.prototype) is similar. Object.create makes a new object and sets it's prototype to point to the object passed in. When you do this you are replacing paidUserCreator.prototype with a new object that is prototype linked to userCreator.prototype. One caveat with this is that if there is anything on paidUserCreator.prototype that you need it will be lost because you are replacing the whole object, not just setting the prototype.
Here's an example where that might bite you:
function userCreator(name, score) {
this.name = name;
}
userCreator.prototype.sayName = function(){console.log("hi");}
function paidUserCreator(paidName, paidScore, accountBalance){
userCreator.call(this, paidName, paidScore);
}
// points to the paidUserCreator function
console.log(paidUserCreator.prototype.constructor)
// replace protoype with new object
paidUserCreator.prototype = Object.create(userCreator.prototype);
// now paidUserCreator.prototype has no constructor property
// so it defers to paidUserCreator
console.log(paidUserCreator.prototype.constructor)
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.
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());