prototypal inheritance concept in javascript as a prototype based language

☆樱花仙子☆ 提交于 2019-11-28 19:52:43

Classical inheritance is about extending types of things. Say you have a class, like Bike. When you want extend the behaviour, you have to design a new type of bike (like MotorBike).

It's like building a factory - you make lots of blueprints, and blueprints that reference those blueprints, but in order to ride one you have to take the blueprint and make something from it.

Prototype-based inheritance is about extending things themselves. Say you have a way of making Bike objects. You take one of these Bikes into your garage, and you strap a jet engine to it.

This is not according to the blueprint. This is something you've done to this particular bike. But your friends see your contraption and want one too. So instead of making a blueprint for your new design, you stick up a sign saying "JetBike factory" and just start making more of them. And every time you can't remember how something fits together, instead of looking at a blueprint you just look at your original bike. Your original bike is the prototype bike, and all the new bikes are based on it.

Now, for a genuine 6-year-old, that's probably where I'd stop (if I hadn't lost them already), but in reality prototype-based inheritance doesn't just construct copies, it does something even cooler - it actually links the new JetBike objects to the original prototype bike you have in your garage. If you replace the suspension on your prototype bike, then all your friends' bikes will also magically have their suspension replaced as well.

Let's look at some JS-ish pseudo-code:

function Bike() {
    this.wheels = 2;
}
Bike.prototype = {
    ride: function() {
        // Ride the bike
    },
    crash: function() {
        // Fall off the bike
    }
};

function JetBike() {
    this.engines = 2;
}
// Start with an ordinary bike
JetBike.prototype = new Bike();
// Modify it
JetBike.prototype.fly = function () {
    // Engage thrusters and head for the ramp
};

Javascript is an object oriented language that is unique in that it does not have classes. Instead we use functions to create objects.

All functions have a prototype, which all objects you create using that function will inherit all properties and methods from. Since Javscript does not have classes, you perform inheritance using an actual object to inherit from (as opposed to a class). You can set a function's prototype to an object, allowing all objects you create with that function to inherit all the methods and properties of the function's prototype object.

So if I have a function that creates an object:

function Foo() {

}
Foo.prototype.someProperty = 'blahblahblah';

You can create another function that creates an object, and allow it to inherit an objects properties and methods by setting the functions prototype to that object.

function Bar() {

}
Bar.prototype = new Foo();

Then you can access all the stuff that was inherited.

var bar = new Bar();
alert( bar.someProperty ); // blahblahblah
Dariush Jafari

Unlike most other object-oriented languages, JavaScript doesn’t actually have a concept of classes. In most other object-oriented languages you would instantiate an instance of a particular class, but that is not the case in JavaScript.
In JavaScript, objects can create new objects, and objects can inherit from other objects.
This whole concept is called prototypal inheritance.

but how we can make an object?
Simply you can create a generic object with {}.

var a = {};
a.prop = "myprop";
console.log(a); //Object { prop="myprop" }

you cannot create instance of a because it is not a function. in other words it has not special internal method [[Construct]].

In JavaScript any function can also be instantiated as an object. The function below is a simple function which takes a name and saves it to the current context:

function User( name ) {
   this.name = name;
}

We can see that User is instance of Function:

alert(User instanceof Function); //true

Create a new instance of that function, with the specified name:

var me = new User( "My Name" ); 

We can see that its name has been set as a property of itself:

alert( me.name == "My Name" ); //true

And that it is an instance of the User object:

alert( me.constructor == User ); //true

Now, since User() is just a function, what happens when we treat it as such?

User( "Test" );

Since its this context wasn't set, it defaults to the global window object, meaning that window.name is equal to the name provided:

alert( window.name == "Test" ); //true

The constructor property exists on every object and will always point back to the function that created it. This way, you should be able to effectively duplicate the object, creating a new one of the same base class but not with the same properties. An example of this can be seen below:

var you = new me.constructor();

We can see that the constructors are, in fact, the same:

alert( me.constructor == you.constructor ); //true

Prototype And Public Methods

Prototype simply contains an object that will act as a base reference for all new copies of its parent object. Essentially, any property of the prototype will be available on every instance of that object. This creation/reference process gives us a cheap version of inheritance.
Since an object prototype is just an object, you can attach new properties to them, just like any other object. Attaching new properties to a prototype will make them a part of every object instantiated from the original prototype, effectively making all the properties public. example:

function User( name, age ){
   this.name = name;
   this.age = age;
}

Adding methods and properties to the prototype property of the constructor function is another way to add functionality to the objects this constructor produces. Let's add one more property, CardNo and a getName() method:

User.prototype.CardNo='12345';
User.prototype.getName = function(){
  return this.name;
};

And add another function to the prototype. Notice that the context is going to be within the instantiated object.

User.prototype.getAge = function(){
   return this.age;
};

Instantiate a new User object:

var user = new User( "Bob", 44 );

We can see that the two methods we attached are with the object, with proper contexts:

alert( user.getName() == "Bob" ); //true
alert( user.getAge() == 44 ); //true

So every function in javascript has a prototype property. Its initial value is an empty object ({}). Notice that generic objects (not functions) don't have the prototype property:

alert( user.prototype ); //undefined (and it is not useful even you define it)

Delegation

When you try to access a property of user, say user.name the JavaScript engine will look through all of the properties of the object searching for one called name and, if it finds it, will return its value:

alert( user.name );

What if the javascript engine cannot find the property? It will identify the prototype of the constructor function used to create this object (same as if you do user.constructor.prototype). If the property is found in the prototype, this property is used:

alert(user.CardNo); // "12345"

and so...
If you want to distinguish between the object's own properties versus the prototype's properties, use hasOwnProperty(). Try:

alert( user.hasOwnProperty('name') ); //true
alert( user.hasOwnProperty('CardNo') ); //false

Private Methods

When you directly set a property for a function, it will be private. example:

function User()
{
    var prop="myprop";
    function disp(){
       alert("this is a private function!");
    }
}
var we = new User();
alert(we.prop); //undefined
we.disp(); // Fails, as disp is not a public property of the object

Privileged Methods

Privileged methods is a term coined by Douglas Crockford to refer to methods that are able to view and manipulate private variables (within an object) while still being accessible to users as a public method. example:
Create a new User object constructor:

function User( name, age ) {
   //Attempt to figure out the year that the user was born:
   var year = (new Date()).getFullYear() – age;

   //Create a new Privileged method that has access to the year variable, but is still publically available:
   this.getYearBorn = function(){
      return year;
   };
}

Create a new instance of the user object:

var user = new User( "Bob", 44 );

Verify that the year returned is correct:

alert( user.getYearBorn() == 1962 ); //true

And notice that we're not able to access the private year property of the object:

alert( user.year == null ); //true

In essence, privileged methods are dynamically generated methods, because they’re added to the object at runtime, rather than when the code is first compiled. While this technique is computationally more expensive than binding a simple method to the object prototype, it is also much more powerful and flexible.

Static Methods

The premise behind static methods is virtually identical to that of any other normal function. The primary difference, however, is that the functions exist as static properties of an object. As a property, they are not accessible within the context of an instance of that object; they are only available in the same context as the main object itself. For those familiar with traditional classlike inheritance, this is sort of like a static class method.
In reality, the only advantage to writing code this way is to keep object namespaces clean.
A static method attached to the User object:

function User(){}
User.cloneUser = function( user ) {
   //Create, and return, a new user
   return new User( user.getName(), user.getAge() );
};

The cloneUser function is only accessible by User:

var me = new User();
me.cloneUser(me); //Uncaught TypeError: Object #<User> has no method 'cloneUser' 

Interesting challenge :-)

First of all I would never try to explain this to anyone by just using words, but I'll give it a try :-)

"Prototypal inheritance is like a pokemon that can steal powers from other pokemons."

Think that you could create your own pokemon. You can decide how big it is, what color it is etc. (constructor). Then you can give that pokemon powers (prototypes). You can spawn as many of these pokemons as you want. What prototypal inheritance gives you is the possibility to let one, several or all these pokemons steal powers from other pokemons. You can even steal powers from pokemons that has already stolen powers from an other pokemon. This creates a whole new range of superpowerful pokemons.

Maybe a bit silly, but it reflects how powerful prototypal inheritance is... in a pokemon sense :-)

Prototypal inheritance is like a son carrying his father on his back everywhere he goes. If someone asks the son, "what color are your shoes?" He would respond with his shoe color, unless he is barefoot, then he'd respond with his dads shoe color.

/* Here is simple way how to inherit objects properties and methods from others object by using prototyping inheritance in plain java script.*/
(function() {  
      // get dom elements for display output`enter code here
      var engTeacherPara = document.getElementById("engTeacher");
      var chemTeacherPara = document.getElementById("chemTeacher");
      // base class 
      var SchoolStaff = function(name, id) {
          this.name = name;
          this.id = id;
        }
        // method on the SchoolStaff object
      SchoolStaff.prototype.print = function() {
        return "Name : " + this.name + " Employee id: " + this.id;
      }

      SchoolStaff.prototype.sayHello = function() {
        return "Hello Mr : " + this.name;
      }

      // sub class engTeacher
      var EngTeacher = function(name, id, salary) {
          SchoolStaff.call(this, name, id);
          this.salary = salary;
        }
        // Inherit the SchoolStaff prototype
      EngTeacher.prototype = Object.create(SchoolStaff.prototype);

      // Set the engTeacher constructor to engTeacher object
      EngTeacher.prototype.constructor = EngTeacher;

      // method on engTeacher object
      EngTeacher.prototype.print = function() {
        return "Name : " + this.name + " Salary : " + this.salary + " Employee id: " + this.id;
      }

      // sub class chemTeacher
      var ChemTeacher = function(name, id, salary, bonus) {
          EngTeacher.call(this, name, id, salary);
          this.bonus = bonus;
        }
        // Inherit the SchoolStaff prototype
      ChemTeacher.prototype = Object.create(EngTeacher.prototype);

      // Set the engTeacher constructor to engTeacher object
      ChemTeacher.prototype.constructor = ChemTeacher;

      // method on engTeacher object
      ChemTeacher.prototype.print = function() {
        console.log("Name : " + this.name + " Salary : " + this.salary + " Employee id: " + this.id + " bonus : " + this.bonus);
      }

      // create new objcts and check sub class have base class methods access
      var schoolStaff = new SchoolStaff("Base Class", 100);
      console.log(schoolStaff.sayHello()); // Hello Mr : Base Class

      var engTeacher = new EngTeacher("Eng Teacher", 1001, 20000);
      engTeacherPara.innerHTML = engTeacher.sayHello(); // Hello Mr : Eng Teacher  

      var chemTeacher = new ChemTeacher("Chem Teacher", 1001, 30000, 4000);
      chemTeacherPara.innerHTML = chemTeacher.sayHello(); // Hello Mr : Chem Teacher
    })();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!