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;
}
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've recently seen JavaScript-code in which getter- and setter-methods where defined on the prototype-object on a constructor method.
For example:
Person.prototype.getFirstName = function() {
return this.firstName;
}
Is this correct?
I mean:
'this' points to the describer of the the object upon which the method was called.
What happens when I call ...
console.log(Person.getFirstName());
... without making an object prior?
Moreover:
Is there a general rule when to attach properties to the constructor-method and when to attach to the prototype-object?
From my view is attaching to the prototype correct if you don't necessarily have to create an object. Because the method doesn't use values of an object which have to set object-individually.
What happens when I call ...
console.log(Person.getFirstName());
... without making an object prior?
You get an error, Person has no getFirstName property.
Is there a general rule when to attach properties to the constructor-method and when to attach to the prototype-object?
Yes:
If you want the method to be available on objects created via the constructor function (e.g., on obj in var obj = new Person()), put the method on the constructor function's prototype object (shared) or assign the method to the object within the constructor by assigning to a property on this (not shared).
If you want the method to be available on the constructor function itself, the way some of the built-in JavaScript methods are (like Date.parse or Object.create), assign it to a property on the constructor:
Person.doSomething = function() {
// ...
};
Those methods are not specific to objects created by the constructor (this within them is a reference to the constructor function itself, unless you do something to make it different).
If you're coming from a class-based language, a very loose analogy is that properties (including methods) you assign to the prototype object on the constructor or to this within the constructor are instance properties, and ones you assign to the constructor itself are static properties. It's a very loose analogy, but sometimes helpful.
Here's a full example in the old ES5 and earlier syntax:
function Person(name) {
this.getName = function() {
return name;
};
}
Person.prototype.sayHello = function() {
console.log("Hello, my name is " + this.getName());
};
Person.copy = function(other) {
return new Person(other.getName());
};
// Usage example
var joe = new Person("Joe");
joe.sayHello();
console.log("joe's name is " + joe.getName());
var joeagain = Person.copy(joe);
joeagain.sayHello();
In the above:
getName is available on instances created by new Person. It's created separately for each object and is not shared with other instances. It lets us get the person's name, which in this example is read-only.
sayHello is available on instances created by new Person because they inherit it from their prototype, which is assigned to them by new Person from the Person.prototype property. It's shared between instances.
copy is not available on instances (joe.copy() would be an error), it's a property on Person itself. In this case we use it to copy instances, but it could be for anything.
Prototypes get inherited by instantiating it with new keyword
So the code
var Person = function(){}
Person.prototype.getFirstName = function() {
return this.firstName;
}
Person.prototype.firstName = "test";
console.log(Person.getFirstName()); // Throw Uncaught TypeError
Correct method is:
var Person2 = new Person()
Person2.getFirstName() // "test"
To test this Object:
so Prototype of Person is set to this Object of Person2 (Inheritance)
This is similar to Class as in Java or C# language.
Personally I'm not fond of adding a getter to the prototype if all you want is to access the instance values. You can already access those values via the instance:
function Person(name) {
this.firstname = name;
}
Person.prototype.getFirstname = function() {
return this.firstname;
}
var p = new Person('o-o');
console.log(p.firstname); //o-o
console.log(p.getFirstname()); //o-o
You could add a getter to the prototype to pass a different context:
var firstname = Person.prototype.getFirstname.call({firstname: 'other'});
console.log(firstname); // other
If so it'd make sense to add a getter to the prototype to add up some computation:
Person.prototype.getFirstname = function() {
return new Date().toISOString + ': ' + this.firstname;
};
If that strategy suits your needs, you could orchestrate your code differently:
var common = {
getValue = function(propName) {
return new Date().toISOString() + ': ' + this[propName];
}
};
function Person(name) {
this.firstname = name;
}
$.extend(Person.prototype, common); //jQuery extend
var p = new Person('o-o');
console.log(p.firstname); //o-o
console.log(p.getValue('firstname')); //today: o-o
Extend your prototype with a versatile common: add logging information during development and drop those superfluous logging information in production.
On the MDN JavaScript guide, under the "Property inheritance revisited" section, it explains some of the subtleties of property inheritance.
The one in particular I'm curious about is an example given about an incrementing id:
var idCounter = 1;
function Employee (name, dept) {
this.name = name || "";
this.dept = dept || "general";
this.id = idCounter++;
}
function Manager (name, dept, reports) {...}
Manager.prototype = new Employee;
function WorkerBee (name, dept, projs) {...}
WorkerBee.prototype = new Employee;
function Engineer (name, projs, mach) {...}
Engineer.prototype = new WorkerBee;
function SalesPerson (name, projs, quota) {...}
SalesPerson.prototype = new WorkerBee;
var mac = new Engineer("Wood, Mac");
Basically, it goes on to say that the completed version of this (each constructor has a 'base' property which also calls the constructor above them in the prototype chain) will mean mac.id will be 5.
I understand that every time an Employee object is created the id value gets incremented by 1, but exactly when are the 4 times before creating 'mac' that an Employee object has been created?
Would be grateful if anyone could give me the process in step by step form.
edit - the page in question: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#Global_information_in_constructors
Using new will call the constructor function. Whenever the constructor function is called (either by new, or the usual ways, (), call or apply), the id will be incremented. So let's count:
Manager.prototype = new Employee; //1
//...
WorkerBee.prototype = new Employee; //2
This is two so far. And if you take into account this important sentence under the code:
Further assume that the definitions omitted here have the base
property and call the constructor above them in the prototype chain.
This basically means that the {...} parts in the code are something like this:
function Manager (name, dept, reports) {
Employee.apply(this, arguments);
}
This jsFiddle shows the code without these ellipses (minimal implementation).
So these will all call the Employee function:
Engineer.prototype = new WorkerBee; //3
//...
SalesPerson.prototype = new WorkerBee; //4
//...
var mac = new Engineer("Wood, Mac"); //5
John Resig has an excellent article, and simple helper function, on how to use class-based inheritance. This makes it easier to inherit from a base class, without calling the constructor.
Here's my own explanation:
In order for Manager to inherit from Employee, Manager.prototype must actually be an instance of an Employee. So, Manager.prototype = new Employee will actually execute the Employee constructor immediately.
The only way around this, is to put the constructor logic into a separate method, such as init:
function Employee() { /* EMPTY CONSTRUCTOR */ }
Employee.prototype.init = function(name, dept) {
this.name = name || "";
this.dept = dept || "general";
this.id = idCounter++;
}
function Manager(name, dept, reports) {
this.init(name, dept); // Calls the base constructor
}
Manager.prototype = new Employee();
When reading https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call for the section "Using call to chain constructors for an object":
function Product(name, price) {
this.name = name;
this.price = price;
if (price < 0)
throw RangeError('Cannot create product "' + name + '" with a negative price');
return this;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
Food.prototype = Object.create(Product.prototype);
function Toy(name, price) {
Product.call(this, name, price);
this.category = 'toy';
}
Toy.prototype = Object.create(Product.prototype);
var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);
I have read that a object's prototype is actually a object itself that points to the constructor's properties memory locations.
In function Food(name, price) it inherits the constructor's Product's properties with Product.call(this). What is Food.prototype = Object.create(Product.prototype); doing? Is it adding another prototype to Food(if that is even possible to have 2 prototypes)? Or is it appending to Food's prototype with the same prototype values of Product(which it already inherited so doesn't make sense to me ether)?
The essence of the problem cam be summarized as "why would you need to set prototypes at all"? In other words, why this is not sufficient to call the base class constructor and not to set the prototype?
The trick is that you could possibly not set the child class function's prototype! Your trivial example would work fine without it. Comment out the line and you will find that the code works with and without this line:
Food.prototype = Object.create(Product.prototype);
This is because all your object properties are set in constructors and by chaining constructors (calling the base class constructor) you have all the properties set on child class instances.
Consider however this:
function Base() {
this.BaseClassMethod = function() {}
}
vs
function Base() {
}
Base.prototype.BaseClassMethod = function() {}
As you can see, there are no fields but a method. Semantically, both snippets define a constructor function that creates instances having the sole BaseClassMethod method. However, in the first snippet there is a new extra function created for each created instance of the class, while in the second snippet the method definition is shared.
This very simple example shows that the same semantics can be achieved in different ways that have different profiles - in the above example is was at least the different memory footprint.
Yet another difference between these two is that in the latter, the function can be redefined somewhere in the future and the new version affects all previously created instances while in the first snippet what you can do is to change the definition in specific instances but not easily "in all previously created instances".
Whether or not this is your goal is another story. You can freely choose between these two ways of assigning methods to classes.
And there lies the answer to your question: without setting the prototype chain, methods defined in base class prototype (the latter snippet) would not be inherited if you only called the base class constructor from the child class constructor.
In other words, calling both the base class constructor and setting the prototype chain makes your inheritance independent on the way methods are defined in the base class.
Let's let code speak for itself. Object.create basically does this:
Object.create = function (o) {
//Object.create equals an anonymous function that accepts one parameter, 'o'.
function F() {};
//Create a new function called 'F' which is just an empty object.
F.prototype = o;
//the prototype of the 'F' function should point to the
//parameter of the anonymous function.
return new F();
//create a new constructor function based off of the 'F' function.
};
Hope this helps. Cheers
Food.prototype = Object.create(Product.prototype) is like extends in other languages. Product.call(this) is like super. With a helper and following conventions it helps to see this relation:
Function.prototype.inherits = function(parent) {
this.prototype = Object.create(parent.prototype); // inherit parent's prototype
this.prototype.constructor = this; // point to the right constructor
};
// A "class"
var Product = (function(){
// constructor
function Product(name, price) {
this.name = name;
this.price = price;
}
return Product;
}());
var Food = (function(_super){
Food.inherits(Product); // inherit Product's prototype methods
function Food(name, price) {
// call "super" to inherit instance properties
_super.call(this, name, price);
this.category = 'food';
}
}(Product)); // the parent class AKA "super"
It is not 100% equivalent, but this should give you a general idea of how inheritance works in JS compared to other languages. It can look pretty similar as you see.
In function Food(name, price) it inherits the constructor's Product's properties with Product.call(this).
Not really. It applies the Product's constructor to the new Food instance, executing its code with e.g. the negative price check.
A "byproduct" is that the constructor creates instance-specific properties on the object, yes.
What is Food.prototype = Object.create(Product.prototype); doing? Is it adding another prototype to Food(if that is even possible to have 2 prototypes)?
Exactly. It is chaining the prototypes. The instances of Food that are created by new Food will inherit properties (including methods) from Food.prototype, which will (by that statement) inherit properties from Product.prototype.
You can't see much of this behaviour currently as your prototype objects do not have any methods yet. Add some (maybe an "output" method?) and check the results.
Simple minimalistic inheritance library: (2kb minified) https://github.com/haroldiedema/joii
It basically allows you to do the following (and more):
// First (bottom level)
var Person = new Class(function() {
this.name = "Unknown Person";
});
// Employee, extend on Person & apply the Role property.
var Employee = new Class({ extends: Person }, function() {
this.name = 'Unknown Employee';
this.role = 'Employee';
this.getValue = function() {
return "Hello World";
}
});
// 3rd level, extend on Employee. Modify existing properties.
var Manager = new Class({ extends: Employee }, function() {
// Overwrite the value of 'role'.
this.role = this.role + ': Manager';
// Class constructor to apply the given 'name' value.
this.__construct = function(name) {
this.name = name;
}
// Parent inheritance & override
this.getValue = function() {
return this.parent.getValue().toUpperCase();
}
});
// And to use the final result:
var myManager = new Manager("John Smith");
console.log( myManager.name ); // John Smith
console.log( myManager.role ); // Manager
console.log( myManager.getValue() ); // HELLO WORLD
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));