Difference between two function placements - javascript

What would be the difference between the following two ways of attaching a method(?) to a parent function:
var Person = function(first, last) {
this.first = first;
this.last = last;
};
Person.prototype.personMethod = function() {
// ...
};
And:
var Person = function(first, last) {
this.first = first;
this.last = last;
this.personMethod = function() {
// ...
};
}

In the first approach, the method is put onto the prototype. Every instance will share the same personMethod because every instance inherits from Person.prototype.
var Person = function(first, last) {
this.first = first;
this.last = last;
};
Person.prototype.personMethod = function() {
// ...
};
const p1 = new Person();
const p2 = new Person();
console.log(p1.personMethod === p2.personMethod);
console.log(p1.hasOwnProperty('personMethod'));
console.log(Object.getPrototypeOf(p1).hasOwnProperty('personMethod'));
console.log(Object.getPrototypeOf(p1) === Person.prototype);
In the second approach, every instance has its own separate method, and it's not on the prototype.
var Person = function(first, last) {
this.first = first;
this.last = last;
this.personMethod = function() {
// ...
};
}
const p1 = new Person();
const p2 = new Person();
console.log(p1.personMethod === p2.personMethod);
console.log(p1.hasOwnProperty('personMethod'));
In modern JavaScript, it's usually preferable to use a class instead, which puts methods onto the prototype.
class Person {
constructor(first, last) {
this.first = first;
this.last = last;
}
personMethod(){}
};
const p1 = new Person();
const p2 = new Person();
console.log(p1.personMethod === p2.personMethod);
console.log(p1.hasOwnProperty('personMethod'));
console.log(Object.getPrototypeOf(p1).hasOwnProperty('personMethod'));
console.log(Object.getPrototypeOf(p1) === Person.prototype);
Assigning the function inside the constructor can be useful if you want the function to close over a variable only scoped to the constructor, which wouldn't work for methods if the variable isn't set to the instance.
var Person = function(first, last) {
// say we don't want to assign these arguments to the instance
// but we can still do
this.getName = () => first + ' ' + last;
}
const p = new Person('John', 'Doe');
console.log(p.getName());

Related

prototype inheritance is wrong

I created a person constructor and I take a firstname = fn, and lastname = ln, and dateofbirth = dob.
That Code is :
function Person(fn, ln, dob){
this.fn = fn;
this.ln = ln;
this.dob = new Date(dob);
}
and also I added prototype
Person.prototype.calcAge = function(){
const diff = Date.now() - this.dob.getTime();
const age = new Date(diff);
return Math.abs(age.getUTCFullYear() - 1970);
}
This is my first Person constructor.
and second constructor i am taken as a customer constructor and that code is :
function Customer(fn,ln,phone,membership){
Person.call(this,fn,ln);
this.phone = phone;
this.membership = membership;
}
And I am inheriting prototype from person to customer
//Inheriting Person Prototype
Customer.prototype = Object.create(Person.prototype);
// Making Customer Prototype
Customer.prototype.constructor = Customer;
And i am console logging :
const Customer1 = new Customer('Sairam', 'Gudiputis', '790-139-7848', 'Premium');
console.log(Customer1)
but in console i am getting invalid date of birth that i am not used in customer..
function Person(fn, ln, dob){
this.fn = fn;
this.ln = ln;
this.dob = new Date(dob);
}
Person.prototype.calcAge = function(){
const diff = Date.now() - this.dob.getTime();
const age = new Date(diff);
return Math.abs(age.getUTCFullYear() - 1970);
}
function Customer(fn,ln,phone,membership){
Person.call(this,fn,ln);
this.phone = phone;
this.membership = membership;
}
//Inheriting Person Prototype
Customer.prototype = Object.create(Person.prototype);
// Making Customer Prototype
Customer.prototype.constructor = Customer;
const Customer1 = new Customer('Sairam', 'Gudiputis', '790-139-7848', 'Premium');
console.log(Customer1)
If you don't want dob in Customer, add:
if (!(this instanceof Customer)) {
this.dob = new Date(dob);
}
in Person constructor:
function Person(fn, ln, dob){
this.fn = fn;
this.ln = ln;
if (!(this instanceof Customer)) {
this.dob = new Date(dob);
}
}
Person.prototype.calcAge = function(){
const diff = Date.now() - this.dob.getTime();
const age = new Date(diff);
return Math.abs(age.getUTCFullYear() - 1970);
}
function Customer(fn,ln,phone,membership){
Person.call(this,fn,ln);
this.phone = phone;
this.membership = membership;
}
//Inheriting Person Prototype
Customer.prototype = Object.create(Person.prototype);
// Making Customer Prototype
Customer.prototype.constructor = Customer;
const Customer1 = new Customer('Sairam', 'Gudiputis', '790-139-7848', 'Premium');
console.log(Customer1)

Newly added function to the prototype of the constructor doesn't work when it's called on objects

function userCreator(name,score){
const newUser = Object.create(userFunctions);
newUser.name = name;
newUser.score = score;
return newUser;
}
userFunctions = {
increment: function(){
this.score++;
}
};
userCreator.prototype.foo = function(){
console.log("foo");
};
const user1 = userCreator("Phil",5);
user1.foo();
I try to add a function to my constructure but when I add this function and call it with user1 it says user1.foo() is not a function.
It looks like you want the object prototype to inherit from the userFunctions object, in which case you should set
userCreator.prototype = Object.create(userFunctions);
outside of the constructor. You should also call new on the constructor, and don't return an object from it, in order for <functionName>.prototype to work correctly:
function userCreator(name,score){
this.name = name;
this.score = score;
}
userFunctions = {
increment: function(){
this.score++;
}
};
userCreator.prototype = Object.create(userFunctions);
userCreator.prototype.foo = function(){
console.log("foo");
};
const user1 = new userCreator("Phil",5);
user1.foo();
(technically, you could use return this, but it's superfluous)
The prototype you're assigning the object in userCreator isn't userCreator.prototype, it's userFunctions. So you'd add foo to that, not userCreator.prototype. Also, don't forget to declare userFunctions, at the moment your code is falling prey to what I call The Horror of Implicit Globals.
function userCreator(name,score){
const newUser = Object.create(userFunctions);
newUser.name = name;
newUser.score = score;
return newUser;
}
const userFunctions = { // *** Added const
increment: function(){
this.score++;
}
};
userFunctions.foo = function(){ // *** `userFunctions`, not `userCreator.prototype`
console.log("foo");
};
const user1 = userCreator("Phil",5);
user1.foo();
userCreator.prototype would be used automatically as the prototype of the new object if you were using new userCreator to create the object, but you're doing it manually with Object.create(userFunctions).
Or alternately, get rid of userFunctions and use userCreator.prototype throughout:
function userCreator(name,score){
const newUser = Object.create(userCreator.prototype);
newUser.name = name;
newUser.score = score;
return newUser;
}
userCreator.prototype.increment = function(){
this.score++;
};
userCreator.prototype.foo = function(){
console.log("foo");
};
const user1 = userCreator("Phil",5);
user1.foo();
Just for what it's worth, the version using new:
function UserCreator(name,score){
this.name = name;
this.score = score;
}
UserCreator.prototype.increment = function(){
this.score++;
};
UserCreator.prototype.foo = function(){
console.log("foo");
};
const user1 = new UserCreator("Phil",5);
user1.foo();
or, since you're already using ES2015+ features:
class UserCreator {
constructor(name,score){
this.name = name;
this.score = score;
}
increment() {
this.score++;
}
}
// If for some reason you wanted to add it separately
// from the `class` definition
UserCreator.prototype.foo = function(){
console.log("foo");
};
const user1 = new UserCreator("Phil",5);
user1.foo();
But doing it without new is fine, too, just add to the correct object.
Since you do not use the new syntax in calling userCreator (and it isn't a function that returns an instance of its prototype), you don't use userCreator as a (standard) constructor. Therefore the created objects do not have userCreator.prototype as proto, and so any mutation of userCreator.prototype has no effect on your created object.
You seem to want to have User objects with UserFunctions. In ES6 syntax you would achieve that like this:
class Scorer {
constructor() {
this.score = 0;
}
increment() {
this.score++;
}
}
class User extends Scorer {
constructor(name, score) {
super();
this.name = name;
this.score = score;
}
foo() {
console.log("foo");
}
}
const user1 = new User("Phil", 5);
user1.foo();

create objects using factory in Javascript

I'm having trying to create two objects of type person using factory and on the first try I create the first element and the second attempt instead of creating the second element creates a new element but with the same characteristics as the first element
class Person
function Person(id, name) {
this.id = id;
this.name = name;
}
class Student extends Person
function Student(id, name) {
Person.call(this, id, name);
}
class Teacher extends Person
function Teacher(id, name) {
Person.call(this, id, name);
}
using function factory to create student and teacher
function Factory() {
this.createPerson = function(type, name) {
var person;
var idStudent = 0;
var idTeacher = 0;
switch (type) {
case "1":
person = new Student(idStudent++, name);
break;
case "2":
person = new Teacher(idTeacher++, name);
break;
}
return person;
}
}
class School has an array of person
function School(id) {
this.persons = [];
this.factory = new Factory();
this.personCreate = null;
this.createStudentAndTeacher = function() {
var type = prompt("Choose ? \n\n[1-Student | 2-Teacher ]");
var name = prompt("Write name?");
if (type !== null) {
this.personCreate = this.factory.createPerson(type,name);
this.persons.push(this.personCreate);
} else {
alert("need to choose");
}
}
}
created by default
var s = new School(1);
var btn = document.createElement('button');
btn.value = "create";
btn.onclick = function(){
s.createStudentAndTeacher();
}
my doubt is when I create the Student object with name "John", return student.id = 0 and student.name = John but when I create the new Student object with name "Elisa", return the same information student.id = 0 and student.name = John and in fact, should return student.id = 1 and student.name = Elisa and if I create new Teacher object with name "Jerry", return the same information student.id = 0 and student.name = John and in fact, should return teacher.id = 0 and teacher.name = Jerry
what I´m doing wrong?
The code has a bug. In the Factory definition, change this
function Factory() {
this.createPerson = function(type, name) {
var person;
var idStudent = 0;
var idTeacher = 0;
to this
function Factory() {
var idStudent = 0;
var idTeacher = 0;
this.createPerson = function(type, name) {
var person;
then use the console, run these lines.
var s = new School();
s.createStudentAndTeacher(); // john
s.createStudentAndTeacher(); // bob
s.persons[0] // id 0:john
s.persons[1] // id 1:bob
Your createPerson is redeclaring idStudent and idTeacher (and resetting them to 0). Try moving that code out of that block.

Accessing this variable from method instance

How do you access the this object from another object instance?
var containerObj = {
Person: function(name){
this.name = name;
}
}
containerObj.Person.prototype.Bag = function(color){
this.color = color;
}
containerObj.Person.prototype.Bag.getOwnerName(){
return name; //I would like to access the name property of this instance of Person
}
var me = new Person("Asif");
var myBag = new me.Bag("black");
myBag.getOwnerName()// Want the method to return Asif
Don't put the constructor on the prototype of another class. Use a factory pattern:
function Person(name) {
this.name = name;
}
Person.prototype.makeBag = function(color) {
return new Bag(color, this);
};
function Bag(color, owner) {
this.color = color;
this.owner = owner;
}
Bag.prototype.getOwnerName = function() {
return this.owner.name;
};
var me = new Person("Asif");
var myBag = me.makeBag("black");
myBag.getOwnerName() // "Asif"
Related patterns to deal with this problem: Prototype for private sub-methods, Javascript - Is it a bad idea to use function constructors within closures?

Javascript Classical Inheritance calling parent

I want to call the super method in an extended javascript 'class' by applying classical inheritance.
function Person(name, age) {
this._name = name;
this._age = age;
}
Person.prototype.exposeInfo = function() {
alert(this._name + ' - ' + this._age);
}
function Employee(name, age) {
this.parent.constructor.call(this, name, age);
}
Employee.prototype.exposeInfo = function() {
alert('Call employee');
this.parent.exposeInfo();
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.parent = Person.prototype;
var p1 = new Person('John Doe', 30);
p1.exposeInfo();
var p2 = new Employee('John Foobar (empl.)', 35);
p2.exposeInfo();
JS Fiddle
The problem is that the method is not being called in the extended class, but only in the parent (Person).
That's because the overriding exposeInfo is being attached to the former prototype object, which is then replaced:
Employee.prototype = Object.create(Person.prototype);
You'll want to reverse the order, attaching methods after creating the prototype:
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.parent = Person.prototype;
Employee.prototype.exposeInfo = function() {
// ...
}
You'll also need to use .call() or .apply() with exposeInfo as you did with the constructor:
Employee.prototype.exposeInfo = function() {
alert('Call employee');
this.parent.exposeInfo.apply(this, arguments);
}
Otherwise, the value of this will be determined by the last member operator:
// so, calling:
this.parent.exposeInfo();
// is equivalent to:
alert(this.parent._name + ' - ' + this.parent._age);
// ...
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.parent = Person.prototype;
Employee.prototype.exposeInfo = function() {
this.parent.exposeInfo.apply(this, arguments);
// ...
}
It's not going to work.
Example:
// ...
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.parent = Person.prototype;
Employee.prototype.exposeInfo = function() {
this.parent.exposeInfo.apply(this, arguments);
// ...
}
ParttimeEmployee = Object.create(Employee.prototype);
ParttimeEmployee.prototype.constructor = ParttimeEmployee;
ParttimeEmployee.prototype.parent = Employee.prototype;
ParttimeEmployee.prototype.exposeInfo = function() {
this.parent.exposeInfo.apply(this, arguments);
// ...
}
var p1 = new Person('Jack', 30);
p1.exposeInfo(); // ok
var p2 = new Employee('Jane', 25);
p2.exposeInfo(); // ok
var p3 = new ParttimeEmployee('John', 20);
p3.exposeInfo(); // infinite recursion !!!
Correct version:
// Person
function Person(name, age) {
this._name = name;
this._age = age;
}
Person.prototype.exposeInfo = function() {
alert(this._name + ' - ' + this._age);
}
// Employee
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.parent = Person.prototype; // <--
Employee.prototype.exposeInfo = function() {
Employee.parent.exposeInfo.apply(this, arguments); // <--
// ...
}
// ParttimeEmployee
ParttimeEmployee = Object.create(Employee.prototype);
ParttimeEmployee.prototype.constructor = ParttimeEmployee;
ParttimeEmployee.parent = Employee.prototype; // <--
ParttimeEmployee.prototype.exposeInfo = function() {
ParttimeEmployee.parent.exposeInfo.apply(this, arguments); // <--
// ...
}
var p1 = new Person('Jack', 30);
p1.exposeInfo(); // ok
var p2 = new Employee('Jane', 25);
p2.exposeInfo(); // ok
var p3 = new ParttimeEmployee('John', 20);
p3.exposeInfo(); // ok

Categories

Resources