6

I am trying to mock inheritance in Javascript using prototype.

I have a function named Model and a type of model => Item.

var Model = function() { 
   this.names = ["name1", "name2"]; 
} 
Model.prototype.Item = function(args) { 
   this.init = function(item_name) { 
      this.names[0] = item_name; // ERROR: Cannot set property '0' of undefined
   } 
}
var m = new Model();
var i = new m.Item();
i.init("New Name"); // ERROR: Cannot set property '0' of undefined

How can I access names array from init() function above?

Michael Gaskill
  • 7,913
  • 10
  • 38
  • 43
Nitin
  • 7,187
  • 6
  • 31
  • 36
  • This line should be failing `var i = new Model.Item();`. Did you mean `(new Model).Item()` or `new Model().Item()`? – cookie monster Jun 04 '14 at 19:48
  • Sorry, copy & paste issue. It is `m.Item()` – Nitin Jun 04 '14 at 19:50
  • 2
    put a `Console.log(this)` in the Item constructor. You'll see this refers to a new object created when you call new m.Item(), not the object created wheny ou call `new Model()`. You've implemented Item as a separate class that happens to be an attribute on the Model prototype object, not an inherited class. Sub classes do not have access to properties in their parent classes. – Steven Wexler Jun 04 '14 at 19:53
  • What youre doing is probably not going to work out the way that you want. When you do `new m.Item();`, the value of `this` is going to be a new `Item()` object that has nothing to do with the `m` object. You could initialize that object using the `Model` function, but that will always give `["name1", "name2"]` instead of whatever actual names were on `m` if modified. – cookie monster Jun 04 '14 at 19:55
  • 1
    What inheritance do you want? Do you want Model to inherit from Item? – Steven Wexler Jun 04 '14 at 19:55
  • ...ultimately putting a constructor on the `.prototype` of another is rarely done if ever because it provides no benefit. There's no implied relationship between the object from which the prototyped constructor was invoked and the new object. – cookie monster Jun 04 '14 at 19:56
  • 2
    ...you don't need to "mock" inheritance in JavaScript. You just need to learn how idiomatic JavaScript inheritance works. – cookie monster Jun 04 '14 at 19:57
  • @StevenWexler Model class should define generic properties and sub classes like Item, Employee should override them. I will instantiate these sub classes. How can I achieve this JS? – Nitin Jun 04 '14 at 20:00
  • So the inheritance pattern should be an Employee extends Model which has a property called Item? Should names be accessed by new Model().names or new Model().Item.names? – Steven Wexler Jun 04 '14 at 20:01
  • @StevenWexler No no. Both Employee and Item inherit (extend) from Model. Model is the base class. I want to try it using plain JS without using libraries as CookieMonster was suggesting. – Nitin Jun 04 '14 at 20:05
  • Could we place `var m = new Model();` before `Model.prototype.Item =..` & replace `this.names[0]` by `m.names[0]`?would that be a bad practice? – techie_28 Apr 14 '16 at 07:11

5 Answers5

11

Inheritance in Javascript is tricky! Read this post for a great explanation of traditional object oriented inheritance in Javascript: http://blog.slaks.net/2013-09-03/traditional-inheritance-in-javascript/.

var Model = function () {
    this.names = ["name1", "name2"];
};

var Item = function () {
    //When inheriting in Javascript you must 
    //call the inherited function's constructor manually.
    Model.call(this);
};

//Inherit Model's prototype so you get all of Model's methods.
Item.prototype = Object.create(Model.prototype);
Item.prototype.constructor = Item;

Item.prototype.init = function (item_name) {
    this.names[0] = item_name;
};

var Employee = function () {
    Model.call(this);
};

Employee.prototype = Object.create(Model.prototype);
Employee.prototype.constructor = Employee;

var myItem = new Item();
myItem.init("New Name");
//prints New Name, name2
console.log(myItem.names);


var myEmployee = new Employee();
//prints name1, name2
console.log(myEmployee.names);

Analogous code in a more traditional object oriented language (C#):

public class Model
{
    public Model()
    {
        this.Names = new[] {"name1", "name2"};
    }
    public string[] Names { get; set; }
}

public class Item : Model
{
    public Item() : base() { }

    public void init(string item_name)
    {
        this.Names[0] = item_name;
    }
}

public class Employee : Model
{
    public Employee() : base() { }
}

var myItem = new Item();
myItem.init("New Name");
//prints New Name, name2
Console.WriteLine(String.Join(",", myItem.Names));

var myEmployee = new Employee();
//prints name1, name2
Console.WriteLine(String.Join(",", myEmployee.Names));
Michael Gaskill
  • 7,913
  • 10
  • 38
  • 43
Steven Wexler
  • 16,589
  • 8
  • 53
  • 80
  • @StevenWexler Would that be stupid If in the original question `var m = new Model();` is placed before `Model.prototype.Item =..` & subsequently `this.names[0]` be replaced by `m.names[0]`? Im trying to understand the right thing to do – techie_28 Apr 14 '16 at 07:10
  • You're correct. You should define how Model works before you use it. – Steven Wexler Apr 15 '16 at 18:04
  • @StevenWexler so it wont still be a bad OOP practice if done that way? – techie_28 Apr 18 '16 at 07:13
  • You should do what you claim is "stupid" if you want to follow good OOP practices. – Steven Wexler Apr 19 '16 at 19:19
1

The issue you're having is that in the second item Item, your reference to this has no idea about it's "parent" object Model.

One way to re-write this is like so:

var Model = function() { 
   this.names = ["name1", "name2"]; 
}

Model.prototype.init = function(item_name) {
    this.names[0] = item_name;
}
var Item = new Model();
Item.init("New Name");

console.log(i);

Fiddle here: http://jsfiddle.net/BksS3/1/

kcent
  • 939
  • 7
  • 8
0

As far as making this work is concerned, this would work too.

var Model = function() { 
   this.names = ["name1", "name2"]; 
} 
Model.prototype.Item = function(args) { 
   this.init = function(item_name) { 
      this.names[0] = item_name;
   } 
}
var m = new Model();
var i = new m.Item();
i.init.apply(m,["New Name"]); 
Empty
  • 350
  • 2
  • 4
  • 22
0

Manager class object will access all method from Person and Employee. Multilevel Inheritance example

      function Person(firstName,lastName,marks,age,gender) 
     {
      this.firstName = firstName;
      this.lastName = lastName;
      this.age=age;
      this.gender=gender;
     }

      Person.prototype.getFullname = function()
       {
         console.log("Full Name is "+this.firstName +' '+this.lastName);
       }

 function Employee(firstName,lastName, marks, rollno, salary) 
 {

     Person.call(this,firstName,lastName,marks, rollno, salary);
     this.rollno = rollno;
     this.salary=salary;


  }

  function Manager(firstName,lastName, marks, rollno, salary, code) {

      Employee.call(this, firstName,lastName,marks, rollno, salary, code);

      this.code = code;
  }



Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;

Employee.prototype.getSalary = function()
       {
         console.log(`Salary of ${this.firstName} ${this.lastName} is ${this.salary}`);
       }


Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
Manager.prototype.designation = function() {
      console.log("You'r designation is Manager");
  }
var m = new Manager("shankar","singh", 21,100, 40000,"CS12");

 console.log(m);
   m.getFullname();
   m.getSalary();
    m.designation();


</script>
0
    This is how you implement multi-level inheritance in JavaScript.

<script> 
    //Multi Level Inheritance Example
    //Parent Class
    class A{
        constructor()
        {

            this.a=0;       
        }
        setA()
        {
            this.a=10;
        }
    }
    //Child Class
    class B extends A{
        constructor()
        {
            super();//call parent class constructor
            this.b=0;
        }
        setB()
        {
            this.b=20;
        }
    }
    class Addition extends B{
        add()
        {       
            this.setA();
            this.setB();
            return this.a+this.b;
        }
    }
    class Print extends Addition{
        print()
        {
            var result=this.add();
            document.write("<br/>a="+this.a);
            document.write("<br/>b="+this.b);
            document.write("<br/>Addition="+result);
            
                
        }
    }
    //Make Object
    let obj=new Print();
    obj.print();
    /*
    Assignment:
    Make subtraction, multiplication, diuvision classes and print the output as

    ==============
    Two Digit Calculator
    ==============
    a=10
    b=20;
    Addition=30
    Subtraction=-10
    Multiplication=200
    Division:.5

    */
    </script>




Rashid
  • 11
  • 4