Implementation of JavaScript inheritance

Source: Internet
Author: User

Object-oriented and Object-based

Almost every developer has development experience in object-oriented languages (such as C ++, C #, and Java. In traditional object-oriented languages, there are two very important concepts: classes and instances. Class defines the common behaviors and methods of a class of things, while the instance is a specific implementation of the class. We also know that object-oriented programming has three important concepts: encapsulation, inheritance, and polymorphism.

However, in the JavaScript world, all of these features do not seem to exist. JavaScript is not an object-oriented language, but an object-based language. There are some interesting features, such as the fact that everything in JavaScript is an object, including strings, arrays, dates, numbers, and even functions. For example:

// Define a function-add
Function add (a, B ){
Add. invokeTimes ++;
Return a + B;
}
// Because the function itself is also an object, an attribute is defined for function add to record the number of times this function is called.
Add. invokeTimes = 0;

Add (1 + 1 );
Add (2 + 3 );
Console. log (add. invokeTimes); // 2

Simulate classes and inheritance in JavaScript

In the object-oriented language, we use classes to create a custom object. However, everything in JavaScript is an object,So how can I create a custom object?

This requires the introduction of another concept-prototype. We can simply regard prototype as a template, and all newly created custom objects are prototype) A copy of (in fact, it is not a copy but a link, but this link is invisible, giving people the feeling that it is a copy ).

Let's take a look at an example of creating a custom object through prototype:

// Constructor
Function Person (name, sex ){
This. name = name;
This. sex = sex;
}
// Define the prototype of Person. attributes in the prototype can be referenced by custom objects.
Person. prototype = {
GetName: function (){
Return this. name;
},
GetSex: function (){
Return this. sex;
}
}

Here we call the Person function a constructor, that is, a function that creates a user-defined object. It can be seen that JavaScript simulates the class function through constructor and prototype.
Code for creating a custom object (instantiation class:

    var zhang = new Person("ZhangSan", "man");
console.log(zhang.getName()); // "ZhangSan"

var chun = new Person("ChunHua", "woman");
console.log(chun.getName()); // "ChunHua"

When the code var zhang = new Person ("ZhangSan", "man") is executed, the following items are actually done internally:

  • Create a blank Object (new Object ()).
  • Copy the attributes (key-value pairs) in Person. prototype to this empty object (as we mentioned earlier, the internal implementation is not a copy but a hidden link ).
  • Pass this object to the constructor using the this keyword and execute the constructor.
  • Assign this object to the variable zhang.

To prove that the prototype template is not copied to an instantiated object, it is a link method. See the following code:

Function Person (name, sex ){
This. name = name;
This. sex = sex;
}
Person. prototype. age = 20;

Var zhang = new Person ("ZhangSan", "man ");
Console. log (zhang. age); // 20
// Overwrite the age attribute in prototype
Zhang. age = 19;
Console. log (zhang. age); // 19
Delete zhang. age;
// After deleting the instance Property age, the property value is obtained from prototype.
Console. log (zhang. age); // 20

This hidden prototype link implemented inside JavaScript is the gentle soil on which JavaScript depends, and is also the basis for simulating inheritance.

How to implement simple inheritance in JavaScript?
The following example creates an Employee class, which inherits all attributes in prototype from Person.

Function Employee (name, sex, employeeID ){
This. name = name;
This. sex = sex;
This. employeeID = employeeID;
}
// Point the prototype of Employee to an instance of Person
// Because the Person instance can call the method in the Person prototype, the Employee instance can also call all attributes in the Person prototype.
Employee. prototype = new Person ();
Employee. prototype. getEmployeeID = function (){
Return this. employeeID;
};

Var zhang = new Employee ("ZhangSan", "man", "1234 ");
Console. log (zhang. getName (); // "ZhangSan

The inheritance implementation above is rough and has many problems:

  • It is not appropriate to instantiate the Person when creating the Employee constructor and prototype (hereinafter referred to as the class.
  • The constructor of the Employee class cannot call the constructor of the parent class Person, causing repeated value assignment to the name and sex attributes in the Employee constructor.
  • The functions in Employee override the functions with the same name in Person, and there is no overload mechanism (which is a type problem with the previous one ).
  • The syntax for creating JavaScript classes is too fragmented and not as elegant as that in C #/Java.
  • The constructor attribute is incorrect. This will be discussed in the second article.

We will complete this example in Chapter 3.

Implementation of JavaScript inheritance

Because JavaScript itself does not have a complete implementation of classes and inheritance, and we also see that there are many problems through manual implementation, there are already many implementations for this challenging task online:

  • Douglas Crockford-Prototypal Inheritance in JavaScript
  • Douglas Crockford-Classical Inheritance in JavaScript
  • John Resig-Simple JavaScript Inheritance
  • Dean Edwards-A Base Class for JavaScript Inheritance
  • Prototype
  • Mootools
  • Extjs

This series of articles will analyze these implementations one by one to gain a deep understanding of how to implement classes and inheritance in JavaScript.

In the next chapter, we will introduce relevant knowledge in class implementation, such as this, constructor, prototype, and so on.

This chapter focuses on several important attributes (this, constructor, prototype) in JavaScript. These attributes play a vital role in understanding how to implement classes and inheritance in JavaScript.

This

This indicates the current object. If this is used globally, it indicates the current page Object window. If this is used in the function, this indicates what is called Based on the object on which the function is called at runtime. We can also use the apply and call global methods to change the specific point of this in the function.

First, let's look at an example of using this in the global scope:

  <script type="text/javascript">   console.log(this === window); // true   console.log(window.alert === this.alert); // true   console.log(this.parseInt("021", 10)); // 10  </script>  

This in a function is determined at runtime, rather than at function definition, as follows:

// Define a global function foo () {console. log (this. fruit);} // defines a global variable, which is equivalent to window. fruit = "apple"; var fruit = "apple"; // In this case, the function foo points to the window object. // this call method and window. foo (); is a fully equivalent foo (); // "apple" // custom object, and direct the property foo of this object to the global function foo var pack = {fruit: "orange", foo: foo}; // in this case, this in function foo points to window. pack object pack. foo (); // "orange"

The global functions apply and call can be used to change the point of this in the function, as follows:

// Define a global function foo () {console. log (this. fruit);} // defines a global variable var fruit = "apple"; // customizes an object var pack = {fruit: "orange"}; // equivalent to window. foo (); foo. apply (window); // "apple" // this in foo = pack foo. apply (pack); // "orange"

Note: The apply and call functions have the same functions. The only difference is that the parameter definitions of the two functions are different.

Because functions in JavaScript are also objects, we can see the following interesting example:

// Define a global function foo () {if (this = window) {console. log ("this is window. ") ;}} // The function foo is also an object, so you can define the boo attribute of foo as a function foo. boo = function () {if (this = foo) {console. log ("this is foo. ");} else if (this = window) {console. log ("this is window. ") ;}}; // equivalent to window. foo (); // this is window. // you can see that this in the function points to the object foo that calls the function. boo (); // this is foo. // use apply to change the point of this in the function to foo. boo. apply (window); // this is window.

Prototype

We have used prototype Simulation class and inheritance implementation in Chapter 1. Prototype is essentially a JavaScript Object. Each function has a default prototype attribute.
If this function is used to create a custom object, we call it a constructor. For example, the following simple scenario:

// Constructor function Person (name) {this. name = name;} // defines the prototype of Person. attributes in the prototype can be referenced by custom objects. prototype = {getName: function () {return this. name ;}} var zhang = new Person ("ZhangSan"); console. log (zhang. getName (); // "ZhangSan"

As an analogy, we consider the data types in JavaScript, such as String, Number, Array, Object, and Date. We have reason to believe that these types are implemented as constructors in JavaScript, such:

// Define the constructor of the Array, which is a predefined function Array () {//...} of JavaScript (){//...} // initialize the Array instance var arr1 = new Array (1, 56, 34, 12); // However, we prefer the following syntax definition: var arr2 = [1, 56, 34, 12];

At the same time, many methods for Array Operations (such as concat, join, and push) should also be defined in the prototype attribute.
In fact, all the inherent Data Types in JavaScript have the read-only prototype attribute (this is understandable: If you modify the prototype attribute of these types, but we can add our own extension method to it.

// Extend a method to the Array of the inherent JavaScript type to obtain the minimum value. Array. prototype. min = function () {var min = this [0]; for (var I = 1; I <this. length; I ++) {if (this [I] <min) {min = this [I] ;}} return min ;}; // call the min method console on any Array instance. log ([1, 56, 34, 12]. min (); // 1

Note: There is a trap. After adding an extension method to the Array prototype, this extension method will also be recycled when the for-in loop Array is used.
The following code illustrates this (assuming that the min method has been extended to the Array prototype ):

  var arr = [1, 56, 34, 12];  var total = 0;  for (var i in arr) {   total += parseInt(arr[i], 10);  }  console.log(total); // NaN    

The solution is also simple:

  var arr = [1, 56, 34, 12];  var total = 0;  for (var i in arr) {   if (arr.hasOwnProperty(i)) {    total += parseInt(arr[i], 10);   }  }  console.log(total); // 103  

Constructor

Constructor always points to the constructor that creates the current object. For example:

// Equivalent to var foo = new Array (1, 56, 34, 12); var arr = [1, 56, 34, 12]; console. log (arr. constructor = Array); // true // equivalent to var foo = new Function (); var Foo = function () {}; console. log (Foo. constructor = Function); // true // The constructor instantiates an obj object var obj = new Foo (); console. log (obj. constructor = Foo); // true // combine the above two sections of code to obtain the following conclusion console. log (obj. constructor. constructor === Function); // true

But when constructor encounters prototype, interesting things happen.
We know that each function has a default prototype attribute, and the constructor of this prototype points to this function by default. For example:

Function Person (name) {this. name = name ;}; Person. prototype. getName = function () {return this. name ;}; var p = new Person ("ZhangSan"); console. log (p. constructor = Person); // true console. log (Person. prototype. constructor = Person); // true // merge the above two lines of code to obtain the following result console. log (p. constructor. prototype. constructor = Person); // true

At that time, when we re-define the prototype of the function (note: the difference from the previous example is that it is not modified but overwritten), the behavior of the constructor is a bit strange, as shown in the following example:

  function Person(name) {   this.name = name;  };  Person.prototype = {   getName: function() {    return this.name;   }  };  var p = new Person("ZhangSan");  console.log(p.constructor === Person); // false  console.log(Person.prototype.constructor === Person); // false  console.log(p.constructor.prototype.constructor === Person); // false  

Why?
It turns out that when people. prototype is overwritten, it is equivalent to performing the following code operations:

  Person.prototype = new Object({   getName: function() {    return this.name;   }  });  

Constructor always points to the creation of its own constructor, so at this time Person. prototype. constructor = Object, that is:

  function Person(name) {   this.name = name;  };  Person.prototype = {   getName: function() {    return this.name;   }  };  var p = new Person("ZhangSan");  console.log(p.constructor === Object); // true  console.log(Person.prototype.constructor === Object); // true  console.log(p.constructor.prototype.constructor === Object); // true  

How can we fix this problem? The method is also very simple. Just overwrite Person. prototype. constructor again:

  function Person(name) {   this.name = name;  };  Person.prototype = new Object({   getName: function() {    return this.name;   }  });  Person.prototype.constructor = Person;  var p = new Person("ZhangSan");  console.log(p.constructor === Person); // true  console.log(Person.prototype.constructor === Person); // true  console.log(p.constructor.prototype.constructor === Person); // true  

In the next chapter, we will improve the Person-Employee class and inheritance implementation mentioned in the first chapter.

Posted @ Sansheng Shi (512) | comment (1) | edit JavaScript inheritance (1) Object-oriented and Object-based

Almost every developer has development experience in object-oriented languages (such as C ++, C #, and Java. In traditional object-oriented languages, there are two very important concepts: classes and instances. Class defines the common behaviors and methods of a class of things, while the instance is a specific implementation of the class. We also know that object-oriented programming has three important concepts: encapsulation, inheritance, and polymorphism.

However, in the JavaScript world, all of these features do not seem to exist. JavaScript is not an object-oriented language, but an object-based language. There are some interesting features, such as the fact that everything in JavaScript is an object, including strings, arrays, dates, numbers, and even functions. For example:

// Define a function-add
Function add (a, B ){
Add. invokeTimes ++;
Return a + B;
}
// Because the function itself is also an object, an attribute is defined for function add to record the number of times this function is called.
Add. invokeTimes = 0;

Add (1 + 1 );
Add (2 + 3 );
Console. log (add. invokeTimes); // 2

Simulate classes and inheritance in JavaScript

In the object-oriented language, we use classes to create a custom object. However, everything in JavaScript is an object,So how can I create a custom object?

This requires the introduction of another concept-prototype. We can simply regard prototype as a template, and all newly created custom objects are prototype) A copy of (in fact, it is not a copy but a link, but this link is invisible, giving people the feeling that it is a copy ).

Let's take a look at an example of creating a custom object through prototype:

// Constructor
Function Person (name, sex ){
This. name = name;
This. sex = sex;
}
// Define the prototype of Person. attributes in the prototype can be referenced by custom objects.
Person. prototype = {
GetName: function (){
Return this. name;
},
GetSex: function (){
Return this. sex;
}
}

Here we call the Person function a constructor, that is, a function that creates a user-defined object. It can be seen that JavaScript simulates the class function through constructor and prototype.
Code for creating a custom object (instantiation class:

  var zhang = new Person("ZhangSan", "man");
console.log(zhang.getName()); // "ZhangSan"

var chun = new Person("ChunHua", "woman");
console.log(chun.getName()); // "ChunHua"

When the code var zhang = new Person ("ZhangSan", "man") is executed, the following items are actually done internally:

  • Create a blank Object (new Object ()).
  • Copy the attributes (key-value pairs) in Person. prototype to this empty object (as we mentioned earlier, the internal implementation is not a copy but a hidden link ).
  • Pass this object to the constructor using the this keyword and execute the constructor.
  • Assign this object to the variable zhang.

To prove that the prototype template is not copied to an instantiated object, it is a link method. See the following code:

Function Person (name, sex ){
This. name = name;
This. sex = sex;
}
Person. prototype. age = 20;

Var zhang = new Person ("ZhangSan", "man ");
Console. log (zhang. age); // 20
// Overwrite the age attribute in prototype
Zhang. age = 19;
Console. log (zhang. age); // 19
Delete zhang. age;
// After deleting the instance Property age, the property value is obtained from prototype.
Console. log (zhang. age); // 20

This hidden prototype link implemented inside JavaScript is the gentle soil on which JavaScript depends, and is also the basis for simulating inheritance.

How to implement simple inheritance in JavaScript?
The following example creates an Employee class, which inherits all attributes in prototype from Person.

Function Employee (name, sex, employeeID ){
This. name = name;
This. sex = sex;
This. employeeID = employeeID;
}
// Point the prototype of Employee to an instance of Person
// Because the Person instance can call the method in the Person prototype, the Employee instance can also call all attributes in the Person prototype.
Employee. prototype = new Person ();
Employee. prototype. getEmployeeID = function (){
Return this. employeeID;
};

Var zhang = new Employee ("ZhangSan", "man", "1234 ");
Console. log (zhang. getName (); // "ZhangSan

The inheritance implementation above is rough and has many problems:

  • It is not appropriate to instantiate the Person when creating the Employee constructor and prototype (hereinafter referred to as the class.
  • The constructor of the Employee class cannot call the constructor of the parent class Person, causing repeated value assignment to the name and sex attributes in the Employee constructor.
  • The functions in Employee override the functions with the same name in Person, and there is no overload mechanism (which is a type problem with the previous one ).
  • The syntax for creating JavaScript classes is too fragmented and not as elegant as that in C #/Java.
  • The constructor attribute is incorrect. This will be discussed in the second article.

We will complete this example in Chapter 3.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.