Note: The implementation of jClass in this chapter refers to the practice of Simple JavaScript Inheritance.
First let us review the examples introduced in Chapter 1:
function Person(name) {<BR> this.name = name;<BR> }<BR> Person.prototype = {<BR> getName: function() {<BR> return this.name;<BR> }<BR> }<br><br> function Employee(name, employeeID) {<BR> this.name = name;<BR> this.employeeID = employeeID;<BR> }<BR> Employee.prototype = new Person();<BR> Employee.prototype.getEmployeeID = function() {<BR> return this.employeeID;<BR> };<BR> var zhang = new Employee("ZhangSan", "1234");<BR> console.log(zhang.getName()); // "ZhangSan" <BR>
Fix constructor pointing error
From the description of the constructor in the previous article, we know that the constructor of the Employee instance will have a pointing error, as shown below:
var zhang = new Employee("ZhangSan", "1234");<BR> console.log(zhang.constructor === Employee); // false<BR> console.log(zhang.constructor === Object); // true <BR>We need a simple correction:
function Employee(name, employeeID) {<BR> this.name = name;<BR> this.employeeID = employeeID;<BR> }<BR> Employee.prototype = new Person();<BR> Employee.prototype.constructor = Employee;<BR> Employee.prototype.getEmployeeID = function() {<BR> return this.employeeID;<BR> };<BR> var zhang = new Employee("ZhangSan", "1234");<BR> console.log(zhang.constructor === Employee); // true<BR> console.log(zhang.constructor === Object); // false<BR>
It is inappropriate to instantiate Person when creating the Employee class
But on the other hand, we must rely on this mechanism to implement inheritance. The solution is not to initialize the data in the constructor, but to provide a prototype method (such as init) to initialize the data.
// 空的构造函数<BR> function Person() {<BR> }<BR> Person.prototype = {<BR> init: function(name) {<BR> this.name = name;<BR> },<BR> getName: function() {<BR> return this.name;<BR> }<BR> }<BR> // 空的构造函数<BR> function Employee() {<BR> }<BR> // 创建类的阶段不会初始化父类的数据,因为Person是一个空的构造函数<BR> Employee.prototype = new Person();<BR> Employee.prototype.constructor = Employee;<BR> Employee.prototype.init = function(name, employeeID) {<BR> this.name = name;<BR> this.employeeID = employeeID;<BR> };<BR> Employee.prototype.getEmployeeID = function() {<BR> return this.employeeID;<BR> };<BR>In this method, the init function must be called manually after instantiating an object, as follows:
var zhang = new Employee();<BR> zhang.init("ZhangSan", "1234");<BR> console.log(zhang.getName()); // "ZhangSan"<BR>
How to automatically call the init function?
Two effects must be achieved: do not call the init function when constructing a class and automatically call the init function when instantiating an object. It seems that we need to have a status indicator when calling the empty constructor.
// 创建一个全局的状态标示 - 当前是否处于类的构造阶段<BR> var initializing = false;<BR> function Person() {<BR> if (!initializing) {<BR> this.init.apply(this, arguments);<BR> }<BR> }<BR> Person.prototype = {<BR> init: function(name) {<BR> this.name = name;<BR> },<BR> getName: function() {<BR> return this.name;<BR> }<BR> }<BR> function Employee() {<BR> if (!initializing) {<BR> this.init.apply(this, arguments);<BR> }<BR> }<BR> // 标示当前进入类的创建阶段,不会调用init函数<BR> initializing = true;<BR> Employee.prototype = new Person();<BR> Employee.prototype.constructor = Employee;<BR> initializing = false;<BR> Employee.prototype.init = function(name, employeeID) {<BR> this.name = name;<BR> this.employeeID = employeeID;<BR> };<BR> Employee.prototype.getEmployeeID = function() {<BR> return this.employeeID;<BR> };<br><br> // 初始化类实例时,自动调用类的原型函数init,并向init中传递参数<BR> var zhang = new Employee("ZhangSan", "1234");<BR> console.log(zhang.getName()); // "ZhangSan"<BR>But this requires the introduction of global variables, which is a bad sign.
How to avoid introducing global variable initializing?
We need to introduce a global function to simplify the class creation process, while encapsulating internal details to avoid introducing global variables.
// 当前是否处于创建类的阶段<BR> var initializing = false;<BR> function jClass(baseClass, prop) {<BR> // 只接受一个参数的情况 - jClass(prop)<BR> if (typeof (baseClass) === "object") {<BR> prop = baseClass;<BR> baseClass = null;<BR> }<BR> // 本次调用所创建的类(构造函数)<BR> function F() {<BR> // 如果当前处于实例化类的阶段,则调用init原型函数<BR> if (!initializing) {<BR> this.init.apply(this, arguments);<BR> }<BR> }<BR> // 如果此类需要从其它类扩展<BR> if (baseClass) {<BR> initializing = true;<BR> F.prototype = new baseClass();<BR> F.prototype.constructor = F;<BR> initializing = false;<BR> }<BR> // 覆盖父类的同名函数<BR> for (var name in prop) {<BR> if (prop.hasOwnProperty(name)) {<BR> F.prototype[name] = prop[name];<BR> }<BR> }<BR> return F;<BR> };<BR>Methods to use jClass functions to create classes and inherit classes:
var Person = jClass({<BR> init: function(name) {<BR> this.name = name;<BR> },<BR> getName: function() {<BR> return this.name;<BR> }<BR> });<BR> var Employee = jClass(Person, {<BR> init: function(name, employeeID) {<BR> this.name = name;<BR> this.employeeID = employeeID;<BR> },<BR> getEmployeeID: function() {<BR> return this.employeeID;<BR> }<BR> });<br><br> var zhang = new Employee("ZhangSan", "1234");<BR> console.log(zhang.getName()); // "ZhangSan"<BR>OK, now the way to create and instantiate classes looks much more elegant. But there are still obvious flaws here. Employee's initialization function init cannot call the method of the same name of the parent class.
How to call the method of the same name in the parent class?
We can point to the prototype of the parent class (constructor) by providing a base attribute for the instantiated object, as follows:
// 当前是否处于创建类的阶段<BR> var initializing = false;<BR> function jClass(baseClass, prop) {<BR> // 只接受一个参数的情况 - jClass(prop)<BR> if (typeof (baseClass) === "object") {<BR> prop = baseClass;<BR> baseClass = null;<BR> }<BR> // 本次调用所创建的类(构造函数)<BR> function F() {<BR> // 如果当前处于实例化类的阶段,则调用init原型函数<BR> if (!initializing) {<BR> // 如果父类存在,则实例对象的base指向父类的原型<BR> // 这就提供了在实例对象中调用父类方法的途径<BR> if (baseClass) {<BR> this.base = baseClass.prototype;<BR> }<BR> this.init.apply(this, arguments);<BR> }<BR> }<BR> // 如果此类需要从其它类扩展<BR> if (baseClass) {<BR> initializing = true;<BR> F.prototype = new baseClass();<BR> F.prototype.constructor = F;<BR> initializing = false;<BR> }<BR> // 覆盖父类的同名函数<BR> for (var name in prop) {<BR> if (prop.hasOwnProperty(name)) {<BR> F.prototype[name] = prop[name];<BR> }<BR> }<BR> return F;<BR> };<BR>Calling method:
var Person = jClass({<BR> init: function(name) {<BR> this.name = name;<BR> },<BR> getName: function() {<BR> return this.name;<BR> }<BR> });<BR> var Employee = jClass(Person, {<BR> init: function(name, employeeID) {<BR> // 调用父类的原型函数init,注意使用apply函数修改init的this指向<BR> this.base.init.apply(this, [name]);<BR> this.employeeID = employeeID;<BR> },<BR> getEmployeeID: function() {<BR> return this.employeeID;<BR> },<BR> getName: function() {<BR> // 调用父类的原型函数getName<BR> return "Employee name: " + this.base.getName.apply(this);<BR> }<BR> });<br><br> var zhang = new Employee("ZhangSan", "1234");<BR> console.log(zhang.getName()); // "Employee name: ZhangSan"<BR>
So far, we have corrected the shortcomings of manual implementation of inheritance in Chapter 1. Create classes and subclasses through our custom jClass function, initialize data through the prototype method init, and call the prototype function of the parent class through the instance attribute base.
The only shortcoming is that the code for calling the parent class is too long and difficult to understand. Wouldn’t it be better if it could be called as follows:
var Employee = jClass(Person, {<BR> init: function(name, employeeID) {<BR> // 如果能够这样调用,就再好不过了<BR> this.base(name);<BR> this.employeeID = employeeID;<BR> }<BR> });<BR>
Optimize jClass function
// 当前是否处于创建类的阶段<BR> var initializing = false;<BR> function jClass(baseClass, prop) {<BR> // 只接受一个参数的情况 - jClass(prop)<BR> if (typeof (baseClass) === "object") {<BR> prop = baseClass;<BR> baseClass = null;<BR> }<BR> // 本次调用所创建的类(构造函数)<BR> function F() {<BR> // 如果当前处于实例化类的阶段,则调用init原型函数<BR> if (!initializing) {<BR> // 如果父类存在,则实例对象的baseprototype指向父类的原型<BR> // 这就提供了在实例对象中调用父类方法的途径<BR> if (baseClass) {<BR> this.baseprototype = baseClass.prototype;<BR> }<BR> this.init.apply(this, arguments);<BR> }<BR> }<BR> // 如果此类需要从其它类扩展<BR> if (baseClass) {<BR> initializing = true;<BR> F.prototype = new baseClass();<BR> F.prototype.constructor = F;<BR> initializing = false;<BR> }<BR> // 覆盖父类的同名函数<BR> for (var name in prop) {<BR> if (prop.hasOwnProperty(name)) {<BR> // 如果此类继承自父类baseClass并且父类原型中存在同名函数name<BR> if (baseClass &&<BR> typeof (prop[name]) === "function" &&<BR> typeof (F.prototype[name]) === "function") {<br><br> // 重定义函数name - <BR> // 首先在函数上下文设置this.base指向父类原型中的同名函数<BR> // 然后调用函数prop[name],返回函数结果<br><br> // 注意:这里的自执行函数创建了一个上下文,这个上下文返回另一个函数,<BR> // 此函数中可以应用此上下文中的变量,这就是闭包(Closure)。<BR> // 这是JavaScript框架开发中常用的技巧。<BR> F.prototype[name] = (function(name, fn) {<BR> return function() {<BR> this.base = baseClass.prototype[name];<BR> return fn.apply(this, arguments);<BR> };<BR> })(name, prop[name]);<br><br> } else {<BR> F.prototype[name] = prop[name];<BR> }<BR> }<BR> }<BR> return F;<BR> };<BR>At this point, creating classes and subclasses and calling methods are very elegant, please see:
var Person = jClass({<BR> init: function(name) {<BR> this.name = name;<BR> },<BR> getName: function() {<BR> return this.name;<BR> }<BR> });<BR> var Employee = jClass(Person, {<BR> init: function(name, employeeID) {<BR> this.base(name);<BR> this.employeeID = employeeID;<BR> },<BR> getEmployeeID: function() {<BR> return this.employeeID;<BR> },<BR> getName: function() {<BR> return "Employee name: " + this.base();<BR> }<BR> });<br><br> var zhang = new Employee("ZhangSan", "1234");<BR> console.log(zhang.getName()); // "Employee name: ZhangSan"<BR>
So far, we have created a complete function jClass to help us implement classes and inheritance in JavaScript in a more elegant way.
In the following chapters, we will successively analyze the implementation of some of the more popular JavaScript classes and inheritance on the Internet. However, everything remains the same, and those implementations are nothing more than "hype" that shakes up the concepts we mentioned in this chapter, just for the sake of a more elegant way of calling.

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。

foreach不是es6的方法。foreach是es3中一个遍历数组的方法,可以调用数组的每个元素,并将元素传给回调函数进行处理,语法“array.forEach(function(当前元素,索引,数组){...})”;该方法不处理空数组。


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Safe Exam Browser
Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

ZendStudio 13.5.1 Mac
Powerful PHP integrated development environment

SublimeText3 English version
Recommended: Win version, supports code prompts!

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools
