在JavaScript中模拟类(class)及类的继承关系


Posted in Javascript onMay 20, 2016

Javascipt语法不支持"类"(class)[es6已经支持],但是有模拟类的方法。今天我主要谈谈Javascipt中模拟“类”的方法及js中继承的总结和回顾。

js中实现“类”与继承,既是重点,又是难点。很多同学可能都对js中“类”与继承都有所了解,但是深入剖析的时候,感觉力不从心、模棱两可。
我们先来总结一下js定义“类”的几种方法:

方法一:构造函数法

这个方法是比较经典的方法,我们会经常见到。生成实例的时候,使用new关键字。类的属性和方法,还可以定义在构造函数的prototype对象之上。

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

Person.prototype.sayName=function(){
 alert(this.name);
}

var person1 = new Person("张三","29","web frontpage manager");
var person2 = new Person("李四","22","doctor");


person1.sayName(); //弹出"张三"
console.log(person2.name)//输出“李四”

方法二:Object.create()法

方法Object.creat()作为new操作符的替代方案是ES5之后才出来的。用这个方法,"类"就是一个对象,不是函数。

var myMammal = {
 name : 'Herb the Mammal',
 get_name : function () {
 return this.name;
 },
 says : function () {
 return this.saying || '';
 }
}

var myCat = Object.create(myMammal);
myCat.name = 'Henrietta';
myCat.saying = 'meow';
myCat.get_name = function () {
 console.log(this.says + ' ' + this.name + this.says);
}

myCat.get_name();

输出:

function () {
 return this.saying || '';
 } Henriettafunction () {
 return this.saying || '';
 }

目前,各大浏览器的最新版本(包括IE9)都部署了这个方法。如果遇到老式浏览器,可以用下面的代码自行部署。

if (!Object.create) {


Object.create = function (o) {



 function F() {}



F.prototype = o;



return new F();


};

}

方法三:极简主义法

封装

这种方法不使用this和prototype,代码部署起来非常简单。 首先,它也是用一个对象模拟"类"。在这个类里面,定义一个构造函数creatFn(),用来生成实例。

var Dog= {


creatFn: function(){



// some code here


}

};

然后,在creatFn()里面,定义一个实例对象,把这个实例对象作为返回值。

var Dog= {


creatFn: function(){



var dog= {};



dog.name = "狗狗";



dog.makeSound = function(){ alert("汪汪汪"); };



return dog;


}

};

使用的时候,调用creatFn()方法,就可以得到实例对象。

var dog1 = Dog.creatFn();

dog1.makeSound(); // 汪汪汪

这种方法的好处是,容易理解,结构清晰优雅,符合传统的"面向对象编程"的构造,因此可以方便地部署下面的特性。

继承

让一个类继承另一个类,实现起来很方便。只要在前者的creatFn()方法中,调用后者的creatFn()方法即可。 先定义一个Animal类。

var Animal = {


creatFn: function(){



var animal = {};



animal.eat= function(){ alert("吃饭饭"); };



return animal;


}

};

然后,在Dog的creatFn()方法中,调用Animal的creatFn()方法。

var Dog= {


creatFn: function(){



var dog= Animal.creatFn();



dog.name = "狗狗";



dog.makeSound = function(){ alert("汪汪汪"); };



return dog;


}

};

这样得到的Dog实例,就会同时继承Dog类和Animal类。

var dog1= Dog.creatFn();

dog1.eat(); // 吃饭饭

私有属性和私有方法

在creatFn()方法中,只要不是定义在dog对象上的方法和属性,都是私有的。

var Dog= {


creatFn: function(){



var dog= {};



var sound = "汪汪汪";



dog.makeSound = function(){ alert(sound); };



return dog;


}

};

上例的内部变量sound,外部无法读取,只有通过dog的公有方法makeSound()来读取。

var dog1 = Dog.creatFn();

alert(dog1.sound); // undefined

数据共享

有时候,我们需要所有实例对象,能够读写同一项内部数据。这个时候,只要把这个内部数据,封装在类对象的里面、creatFn()方法的外面即可。

var Dog= {


sound : "汪汪汪",


creatFn: function(){



var dog= {};



dog.makeSound = function(){ alert(Dog.sound); };



dog.changeSound = function(x){ Dog.sound = x; };



return dog;


}

};

然后,生成两个实例对象:

var dog1 = Dog.creatFn();

var dog2 = Dog.creatFn();

dog1.makeSound(); // 汪汪汪

这时,如果有一个实例对象,修改了共享的数据,另一个实例对象也会受到影响。

dog2.changeSound("呜呜呜");

dog1.makeSound(); //呜呜呜

js继承

关于继承,网上也有很多资料可以查询,但是很多朋友对其理解的不够深入。讲到继承,假如你不去查资料,猛地一下,可能说不出个所以然来。这就说明我们的基础知识打的不够扎实。没有理解透彻。今天,我站在前辈的基础之上,再来和大家一起回顾一下这个 继承。

继承最常用的两种方式如下:

  • 原型链继承(对象间的继承)
  • 类式继承(构造函数间的继承)

原型链继承

什么是原型链继承?这里我就不说什么定义了。其实就是用prototype继承父级。

举个例子:

function Parent(){
 this.name = 'mike';
} 
function Child(){
 this.age = 12;
}
Child.prototype = new Parent();//Child继承Parent,通过原型,形成链条

var test = new Child();
alert(test.age);
alert(test.name);//得到被继承的属性
//继续原型链继承
function Brother(){ //brother构造
 this.weight = 60;
}
Brother.prototype = new Child();//继续原型链继承
var brother = new Brother();
alert(brother.name);//继承了Parent和Child,弹出mike
alert(brother.age);//弹出12

上面例子,通过原型,形成链条,Child继承了Parent,Brother有继承了Child,最后brother既有Child和Parent的属性,又有自己的属性。这就是原形链的继承。

类式继承(借用构造函数)

类式继承一般是通过运用call或者apply 进行子类型构造函数的内部调用超类型的构造函数。举个例子:

function Parent(age){
 this.name = ['mike','jack','smith'];
 this.age = age;
}

function Child(age){
 Parent.call(this,age);
}
var test = new Child(21);
alert(test.age);//21
alert(test.name);//mike,jack,smith
test.name.push('bill');
alert(test.name);//mike,jack,smith,bill

上面的两种继承是最基本的两种继承方式。

此外还有一些继承方式,我们一起来看一下!

组合继承

组合继承通常是上面两种继承方式组合在一起使用的继承方式。

举例如下:

function Parent(age){
 this.name = ['mike','jack','smith'];
 this.age = age;
}
Parent.prototype.run = function () {
 return this.name + ' are both' + this.age;
};
function Child(age){
 Parent.call(this,age);//对象冒充,给超类型传参
}
Child.prototype = new Parent();//原型链继承
var test = new Child(21);//写new Parent(21)也行
alert(test.run());//mike,jack,smith are both21

原型式继承

和上面讲的原形链式继承只有一字之差,但是不是同一个内容。我们所说的原型式继承,就是我们上节课所讲的,通过Object.create()方式来创建新的类。因为这种方式老式浏览器不支持。因此,假如我们不用Object.create(),也可以有替代法,方式如下:

function obj(o){
 function F(){}
 F.prototype = o;
 return new F();
 }

这个函数,就实现了我们Object.create()创建类的方式!

因此举例如下:

function obj(o){
 function F(){}
 F.prototype = o;
 return new F();
 }
var box = {
 name : 'trigkit4',
 arr : ['brother','sister','baba']
};
var b1 = obj(box);
alert(b1.name);//trigkit4

b1.name = 'mike';
alert(b1.name);//mike

alert(b1.arr);//brother,sister,baba
b1.arr.push('parents');
alert(b1.arr);//brother,sister,baba,parents

var b2 = obj(box);
alert(b2.name);//trigkit4
alert(b2.arr);//brother,sister,baba,parents

寄生式继承

举例如下:

function creatAnother(original){
 var clone=new Object(original);
 clone.sayHi=function(){
 alert("hi")
 };
 return clone;
}
var person={
 name:"haorooms",
 friends:["hao123","zhansan","lisi"]
}

var antherPerson=creatAnother(person);
antherPerson.sayHi();//hi

寄生组合式

function inheritPrototype (subType,superType) {
 var prototype = Object.creat(superType.prototype);
 prototype.constructor = subType;
 subType.prototype = prototype;
};

function SuperType (name) {
 this.name = name;
 this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function () {
 console.log(this.name);
}
function SubType(name, age) {
 //继承属性
 SuperType.call(this,name);
 this.age = age;
}
//继承方法
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge = function () {
 console.log(this.age);
}

var instance = new SubType();

类的继承,基本上就是如上几种方式。下面再简单的说一下ES6的class类吧!

es6实现类

//定义类
class Point {
 constructor(x, y) {
 this.x = x;
 this.y = y;
 }
 toString() {
 return '('+this.x+', '+this.y+')';
 }
}
var point = new Point(2, 3);
point.toString() // (2, 3)
point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true
point.hasOwnProperty('toString') // false
point.__proto__.hasOwnProperty('toString') // true

Class的继承

class ColorPoint extends Point {
 constructor(x, y, color) {
 super(x, y); // 调用父类的constructor(x, y)
 this.color = color;
 } 
 toString() {
 return this.color + ' ' + super.toString(); // 调用父类的toString()
 }
}
Javascript 相关文章推荐
在b/s开发中经常用到的javaScript技术
Aug 23 Javascript
利用jQuary实现文字浮动提示效果示例代码
Dec 26 Javascript
js类定义函数时用prototype与不用的区别示例介绍
Jun 10 Javascript
对JavaScript客户端应用编程的一些建议
Jun 24 Javascript
浅析JavaScript中命名空间namespace模式
Jun 22 Javascript
jQuery根据ID、CLASS、等获取对象的实例
Dec 04 Javascript
点击按钮弹出模态框的一系列操作代码实例
Mar 29 Javascript
微信小程序按顺序同步执行的两种方式
Dec 20 Javascript
Angular 多模块项目构建过程
Feb 13 Javascript
如何在JavaScript中创建具有多个空格的字符串?
Feb 23 Javascript
vue2路由方式--嵌套路由实现方法分析
Mar 06 Javascript
基于element-ui封装可搜索的懒加载tree组件的实现
May 22 Javascript
基于Node.js的JavaScript项目构建工具gulp的使用教程
May 20 #Javascript
JavaScript中用let语句声明作用域的用法讲解
May 20 #Javascript
如何用JavaScript实现动态修改CSS样式表
May 20 #Javascript
JavaScript中的跨浏览器事件操作的基本方法整理
May 20 #Javascript
用JavaScript动态建立或增加CSS样式表的实现方法
May 20 #Javascript
详解JavaScript中的事件流和事件处理程序
May 20 #Javascript
jQuery基础的工厂函数以及定时器的经典实例分析
May 20 #Javascript
You might like
Joomla下利用configuration.php存储简单数据
2010/05/19 PHP
php实现字符串翻转的方法
2015/03/27 PHP
php实现TCP端口检测的方法
2015/04/01 PHP
详解php中反射的应用
2016/03/15 PHP
php判断手机浏览还是web浏览,并执行相应的动作简单实例
2016/07/28 PHP
PHP实现基本留言板功能原理与步骤详解
2020/03/26 PHP
Extjs4 类的定义和扩展实例
2013/06/28 Javascript
js里取容器大小、定位、距离等属性搜集整理
2013/08/19 Javascript
JS 实现列表与多选框选择附预览动画
2014/10/29 Javascript
Nodejs学习笔记之Stream模块
2015/01/13 NodeJs
jquery实现具有嵌套功能的选项卡
2016/02/12 Javascript
Bootstrap的fileinput插件实现多文件上传的方法
2016/09/05 Javascript
jQuery中$.grep() 过滤函数 数组过滤
2016/11/22 Javascript
微信小程序进行微信支付的步骤昂述
2016/12/01 Javascript
AngularJS中使用three.js的实例详解
2017/07/21 Javascript
Vue2.0学习之详解Vue 组件及父子组件通信
2017/12/12 Javascript
关于jquery中attr()和prop()方法的区别
2018/05/28 jQuery
element-ui树形控件后台返回的数据+生成组织树的工具类
2020/03/05 Javascript
在实例中重学JavaScript事件循环
2020/12/03 Javascript
[00:55]2015国际邀请赛中国区预选赛5月23日——28日约战上海
2015/05/25 DOTA
Python中操作文件之write()方法的使用教程
2015/05/25 Python
python Pandas 读取txt表格的实例
2018/04/29 Python
python3.6 tkinter实现屏保小程序
2019/07/30 Python
解决django同步数据库的时候app models表没有成功创建的问题
2019/08/09 Python
CSS3打造磨砂玻璃背景效果
2016/09/28 HTML / CSS
canvas学习总结三之绘制路径-线段
2019/01/31 HTML / CSS
瑞典耳机品牌:URBANISTA
2019/12/03 全球购物
什么是"引用"?申明和使用"引用"要注意哪些问题?
2016/03/03 面试题
物理系毕业生自荐书
2014/06/13 职场文书
师德师风个人自我剖析材料
2014/09/27 职场文书
运动会广播稿200米(5篇)
2014/10/15 职场文书
领导干部作风建设自查报告
2014/10/23 职场文书
2014年设计师工作总结
2014/11/25 职场文书
书法社团活动总结
2015/05/07 职场文书
2016年社区植树节活动总结
2016/03/16 职场文书
python标准库ElementTree处理xml
2022/05/20 Python