JavaScript inheritance Detailed (iii) _JS object-oriented

Source: Internet
Author: User
Tags closure inheritance hasownproperty

Note: The implementation of the Jclass in this chapter refers to the practice of simple JavaScript inheritance .

First, let's look at the examples that are presented in the first chapter:

function person (name) {
THIS.name = name;
}
Person.prototype = {
Getname:function () {
return this.name;
}
}

function Employee (name, EmployeeID) {
THIS.name = name;
This.employeeid = EmployeeID;
}
Employee.prototype = new Person ();
Employee.prototype.getEmployeeID = function () {
return This.employeeid;
};
var Zhang = new Employee ("Zhangsan", "1234");

Correcting constructor Pointing errors

From the description of constructor in the previous article, we know that the constructor of the employee instance will have a pointing error, as follows:

var Zhang = new Employee ("Zhangsan", "1234");
Console.log (Zhang.constructor = = Employee); False

We need a simple fix:
function Employee (name, EmployeeID) {
THIS.name = name;
This.employeeid = EmployeeID;
}
Employee.prototype = new Person ();
Employee.prototype.constructor = Employee;
Employee.prototype.getEmployeeID = function () {
return This.employeeid;
};
var Zhang = new Employee ("Zhangsan", "1234");
Console.log (Zhang.constructor = = Employee); True
Console.log (Zhang.constructor = = = Object); False

It is not appropriate to instantiate a person when creating an employee class

But on the other hand, we must rely on this mechanism to achieve inheritance. The workaround is not to initialize the data in the constructor, but to provide a prototype method (such as Init) to initialize the data.

An empty constructor
function person () {
}
Person.prototype = {
Init:function (name) {
THIS.name = name;
},
Getname:function () {
return this.name;
}
}
An empty constructor
function Employee () {
}
The stage of creating a class does not initialize the data of the parent class because the person is an empty constructor
Employee.prototype = new Person ();
Employee.prototype.constructor = Employee;
Employee.prototype.init = function (name, EmployeeID) {
THIS.name = name;
This.employeeid = EmployeeID;
};
Employee.prototype.getEmployeeID = function () {
return This.employeeid;
};
In this way, the INIT function must be invoked manually after instantiating an object, as follows:
var Zhang = new Employee ();
Zhang.init ("Zhangsan", "1234");
Console.log (Zhang.getname ()); "Zhangsan"

How do I invoke the init function automatically?

The

must have two effects, and the Init function is automatically invoked when the class is constructed without calling the Init function and instantiating the object. It seems that we need to have a status indicator when we call an empty constructor.

Create a global status indicator-whether it is currently in the construction phase of a class
var initializing = false;
function person () {
if (!initializing) {
This.init.apply (this, arguments);
}
}
Person.prototype = {
Init:function (name) {
THIS.name = name;
},
Getname:function () {
return this.name;
}
}
function Employee () {
if (!initializing) {
This.init.apply (this, arguments);
}
}
Marks the creation phase of the current entry into the class and does not invoke the INIT function
initializing = true;
Employee.prototype = new Person ();
Employee.prototype.constructor = Employee;
initializing = false;
Employee.prototype.init = function (name, EmployeeID) {
THIS.name = name;
This.employeeid = EmployeeID;
};
Employee.prototype.getEmployeeID = function () {
return This.employeeid;
};

Initializes the class's prototype function init and passes parameters to init when the class instance is initialized
var Zhang = new Employee ("Zhangsan", "1234");
Console.log (Zhang.getname ()); "Zhangsan"
But this must introduce global variables, which is a bad signal.

How to avoid introducing global variables initializing?

We need to introduce a global function to simplify the creation of classes, while encapsulating internal details to avoid introducing global variables.

is currently in the stage of creating a class
var initializing = false;
function Jclass (BaseClass, prop) {
Conditions that accept only one parameter-jclass (prop)
if (typeof (BaseClass) = = "Object") {
Prop = BaseClass;
BaseClass = null;
}
Class created by this call (constructor)
function F () {
Invokes the INIT prototype function if it is currently at the stage of the instantiation class
if (!initializing) {
This.init.apply (this, arguments);
}
}
If this class needs to be extended from other classes
if (BaseClass) {
initializing = true;
F.prototype = new BaseClass ();
F.prototype.constructor = F;
initializing = false;
}
Overriding a function with the same name as a parent class
for (var name in prop) {
if (Prop.hasownproperty (name)) {
F.prototype[name] = Prop[name];
}
}
return F;
};
Use the Jclass function to create methods for classes and inheriting classes:
var person = Jclass ({
Init:function (name) {
THIS.name = name;
},
Getname:function () {
return this.name;
}
});
var Employee = Jclass (person, {
Init:function (name, EmployeeID) {
THIS.name = name;
This.employeeid = EmployeeID;
},
Getemployeeid:function () {
return This.employeeid;
}
});

var Zhang = new Employee ("Zhangsan", "1234");
Console.log (Zhang.getname ()); "Zhangsan"
OK, now the way to create classes and instantiate classes looks a lot more elegant. But there are obvious flaws in it, employee initialization function Init cannot call the parent class's method of the same name.

How do I call the parent class's method of the same name?

We can point to the prototype of the parent class (constructor) by providing a base attribute for the instantiated object, as follows:

is currently in the stage of creating a class
var initializing = false;
function Jclass (BaseClass, prop) {
Conditions that accept only one parameter-jclass (prop)
if (typeof (BaseClass) = = "Object") {
Prop = BaseClass;
BaseClass = null;
}
Class created by this call (constructor)
function F () {
Invokes the INIT prototype function if it is currently at the stage of the instantiation class
if (!initializing) {
If the parent class exists, the base of the instance object points to the prototype of the parent class
This provides a way to invoke the parent class method in the instance object
if (BaseClass) {
This.base = Baseclass.prototype;
}
This.init.apply (this, arguments);
}
}
If this class needs to be extended from other classes
if (BaseClass) {
initializing = true;
F.prototype = new BaseClass ();
F.prototype.constructor = F;
initializing = false;
}
Overriding a function with the same name as a parent class
for (var name in prop) {
if (Prop.hasownproperty (name)) {
F.prototype[name] = Prop[name];
}
}
return F;
};
Call Mode:
var person = Jclass ({
Init:function (name) {
THIS.name = name;
},
Getname:function () {
return this.name;
}
});
var Employee = Jclass (person, {
Init:function (name, EmployeeID) {
To invoke the prototype function init of the parent class, note using the Apply function to modify the this point of Init
This.base.init.apply (this, [name]);
This.employeeid = EmployeeID;
},
Getemployeeid:function () {
return This.employeeid;
},
Getname:function () {
Invoke the prototype function of the parent class GetName
Return ' Employee name: ' + this.base.getName.apply (this);
}
});

var Zhang = new Employee ("Zhangsan", "1234");
Console.log (Zhang.getname ()); "Employee Name:zhangsan"

So far, we have fixed the drawbacks of manually inheriting in the first chapter. Using our custom Jclass function to create classes and subclasses, initialize the data through the prototype method Init, and invoke the parent class's prototype function through the instance property base.

The only drawback is that the code that invokes the parent class is too long and difficult to understand, and it would be better if you could call it the following way:

var Employee = Jclass (person, {
Init:function (name, EmployeeID) {
It would be better if we could call it that way.
This.base (name);
This.employeeid = EmployeeID;
}
});

Optimizing Jclass Functions

is currently in the stage of creating a class
var initializing = false;
function Jclass (BaseClass, prop) {
Conditions that accept only one parameter-jclass (prop)
if (typeof (BaseClass) = = "Object") {
Prop = BaseClass;
BaseClass = null;
}
Class created by this call (constructor)
function F () {
Invokes the INIT prototype function if it is currently at the stage of the instantiation class
if (!initializing) {
If the parent class exists, the baseprototype of the instance object points to the prototype of the parent class
This provides a way to invoke the parent class method in the instance object
if (BaseClass) {
This.baseprototype = Baseclass.prototype;
}
This.init.apply (this, arguments);
}
}
If this class needs to be extended from other classes
if (BaseClass) {
initializing = true;
F.prototype = new BaseClass ();
F.prototype.constructor = F;
initializing = false;
}
Overriding a function with the same name as a parent class
for (var name in prop) {
if (Prop.hasownproperty (name)) {
If this class inherits from the parent class BaseClass and a function name exists in the parent class prototype
if (BaseClass &&
typeof (Prop[name]) = = = "function" &&
typeof (F.prototype[name]) = = = "function") {

Redefine function name-
First in the function context set this.base points to a function of the same name in the parent class prototype
Then call function Prop[name], return the result of the function

Note: The self execution function here creates a context in which the context returns another function,
The variables in this context can be applied in this function, which is the closure (Closure).
This is a common technique in JavaScript framework development.
F.prototype[name] = (function (name, FN) {
return function () {
This.base = Baseclass.prototype[name];
Return fn.apply (this, arguments);
};
}) (name, Prop[name]);

} else {
F.prototype[name] = Prop[name];
}
}
}
return F;
};
At this point, creating classes and subclasses and calling methods are very elegant, see:
var person = Jclass ({
Init:function (name) {
THIS.name = name;
},
Getname:function () {
return this.name;
}
});
var Employee = Jclass (person, {
Init:function (name, EmployeeID) {
This.base (name);
This.employeeid = EmployeeID;
},
Getemployeeid:function () {
return This.employeeid;
},
Getname:function () {
Return "Employee Name:" + this.base ();
}
});

var Zhang = new Employee ("Zhangsan", "1234");
Console.log (Zhang.getname ()); "Employee Name:zhangsan"

So far, we've created a perfect function jclass that helps us implement classes and inheritance in a more elegant way in JavaScript.

In future chapters, we'll analyze some of the more popular JavaScript classes and inheritance implementations on the web. But same, the realization is nothing more than the concept mentioned in our chapter to the "Hype", for a more elegant way of calling.

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.