Javascript中,实现类与继承的方法和优缺点分析
Javascript是一种弱类型语言,不存在类的概念,但在js中可以模仿类似于JAVA中的类,实现类与继承
第一种方法:利用Javascript中的原型链
//首先定义一个父类
function Animal(name,age){
//定义父类的属性
this.name = name || "Animal";
this.age = age ;
//定义父类的方法
this.sleep = function(){
console.log("这只"+this.name+"正在睡觉!");
};
this.showAge = function(){
console.log("这只"+this.name+"的年龄是"+this.age+"岁!");
}
};
//为父类添加原型方法
Animal.prototype.eat =function(food){
console.log("这只"+this.name+"正在吃"+food+"!")
}
Animal.prototype.weight = 10;
Animal.prototype.bark = function(){
console.log("bark");
}
//Javascript实现继承的方法一:
//原型链法 核心:将父类的实例作为子类的原型
function Cat(){
};
Cat.prototype = new Animal();
Cat.prototype.name = "猫";
Cat.prototype.age = 3;
Cat.prototype.bark = function(){
console.log("喵喵");
}
//测试上面的例子
var cat = new Cat();
console.log(cat.name); //输出猫
console.log(cat.age); //输出 3
console.log(cat.weight); // 输出10
cat.sleep(); //输出 这只猫正在睡觉!
cat.showAge(); //输出 这只猫的年龄是3岁!
cat.eat("鱼"); //输出 这只猫正在吃鱼!
cat.bark(); //输出喵喵
console.log(cat instanceof Animal); //输出 true
console.log(cat instanceof Cat); //输出 true
var Dog = new Function; // 为什么这样写也可以呢? 例子最后将做解释
Dog.prototype = new Animal();
Dog.prototype.name = "狗";
Dog.prototype.age = 4;
Dog.prototype.bark = function(){
console.log("汪汪");
}
var dog = new Dog();
console.log(dog.name); //输出 狗
console.log(dog.age); //输出 4
console.log(dog.weight); //输出 10
dog.sleep(); //输出 这只狗正在睡觉!
dog.eat("骨头"); //输出 这只狗正在吃骨头
dog.bark(); //输出 汪汪
console.log(dog instanceof Dog); //输出true
console.log(dog instanceof Animal); //输出true
console.log(Animal.constructor); //输出 Function
console.log(Cat.constructor); //输出 Function
console.log(Dog.constructor); //输出 Function
console.log(cat.constructor); //输出 function Animal(){...}
console.log(dog.constructor); //输出 function Animal(){...}
/*有上面四行的输出结果可以看书,Animal 父类,以及Cat 和 Dog 子类,都是由Function 创建出来的构造函数,
而 cat 和 dog 是由Animal 父类构建出来的子类 */
原型链法实现继承的特点分析
优点: 1.是非常纯粹的继承关系,实例是子类的实例,也是父类的实例, 2.父类新增原型属性和原型方法,子类都可以访问到 3.简单方便,易于实现
缺点 : 1.想要为子类添加原型属性和原型方法,则必须在new Animal() 语句之后执行 2.无法实现多继承 3.来自原型对象的引用属性是所有实例共享的(由Cat 和 Dog 都可以使用weight 属性 和 eat 方法可以看出) 4.创建子类实例时,无法向父类构造函数传参
第二种方法: 构造函数法
//首先定义一个父类
function Animal(name,age){
//定义父类的属性
this.name = name || "Animal";
this.age = age ;
//定义父类的方法
this.sleep = function(){
console.log("这只"+this.name+"正在睡觉!");
};
this.showAge = function(){
console.log("这只"+this.name+"的年龄是"+this.age+"岁!");
}
};
//为父类添加原型方法
Animal.prototype.eat =function(food){
console.log("这只"+this.name+"正在吃"+food+"!")
}
Animal.prototype.weight = 10;
Animal.prototype.bark = function(){
console.log("bark");
}
//Javascript 实现继承的方法二 :
//构造函数法 核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类,但父类的原型属性和原型方法在子类中不能提现
function Cat(name,age){
Animal.call(this); //使用call方法继承父类的属性和方法
this.name = name || "猫"; //使用子类自己的属性覆盖从父类继承来的属性
this.age = age; //使用子类自己的属性覆盖从父类继承来的属性
this.bark = function(){ //定义子类自己的方法
console.log("喵喵");
}
};
//测试
var cat = new Cat("猫",4); //新创建一个子类实例化对象,并传参
console.log(cat.name); // 输出 猫
console.log(cat.age); //输出 4
console.log(cat.weight); //这一句会报undefined,因为父类的原型属性在子类中无法使用
cat.sleep(); // 输出 这只猫正在睡觉
cat.bark(); //输出喵喵
//cat.eat("鱼"); //这一句会报错,因为父类的原型方法在这里不能使用
cat.showAge(); //输出
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
//上面这两句可以看书,cat 并不属于Animal 父类的实例对象,而只是Cat 子类的实例对象
//总结
/*构造函数法实现继承的方法的特点分析
优点:
1.解决了原型链法中,子类实例对象会共享父类引用属性的问题;
2.创建子类实例对象时,可以向父类传递参数
3.可以实现多继承(通过call多个父类对象)
缺点:
1.实例对象并不是父类的实例对象,而只是子类的实例对象,(举例(小花猫属于猫类,却不属于动物类),这点很不好)
2.只能继承父类的实例属性和实例方法,不能继承父类的原型属性和原型方法
3.无法实现函数的复用,每个子类都有父类实例函数的副本,影响性能
构造函数法实现继承的优缺点分析:
优点: 1.解决了原型链法中,子类实例对象会共享父类引用属性的问题; 2.创建子类实例对象时,可以向父类传递参数 3.可以实现多继承(通过call多个父类对象)
缺点: 1.实例对象并不是父类的实例对象,而只是子类的实例对象,(举例(小花猫属于猫类,却不属于动物类),这点很不好) 2.只能继承父类的实例属性和实例方法,不能继承父类的原型属性和原型方法 3.无法实现函数的复用,每个子类都有父类实例函数的副本,影响性能
第三种方法:实例继承法
//首先定义一个父类
function Animal(name,age){
//定义父类的属性
this.name = name || "Animal";
this.age = age ;
//定义父类的方法
this.sleep = function(){
console.log("这只"+this.name+"正在睡觉!");
};
this.showAge = function(){
console.log("这只"+this.name+"的年龄是"+this.age+"岁!");
}
};
//为父类添加原型方法
Animal.prototype.eat =function(food){
console.log("这只"+this.name+"正在吃"+food+"!")
}
Animal.prototype.weight = 10;
Animal.prototype.bark = function(){
console.log("bark");
}
//Javascript 实现继承的方法二 :
//实例继承 核心:为父类实例添加新特性,作为子类实例返回
function Cat(name,age){
var obj = new Animal(); // 创建一个父类的实例对象obj
//这里为obg添加了一个不可枚举属性 sex
Object.defineProperty(obj, "sex", {
value: "female",
enumerable: false
});
obj.name = "猫"; // 为实例对象添加 属性
obj.age = 3; // 为实例对象添加 属性
obj.bark = function(){ // 为实例对象添加方法
console.log("喵喵");
}
return obj; // 将这个实例对象作为返回值返回
};
//测试代码
var cat = new Cat();
console.log(cat.name); //输出 猫
console.log(cat.age); //输出 3
console.log(cat.weight); // 输出 10
console.log(cat.sex); //输出female
cat.sleep(); // 输出 这只猫正在睡觉
cat.eat("鱼"); // 输出 这只猫正在吃鱼
cat.bark(); //输出 喵喵
console.log(cat instanceof Cat); //输出false
//instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
//instanceof 运算符可以用来判断一个对象是否属于某种对象类型
//instanceof 运算符更好的用途是可以判断一个实例是否属于它的父类
console.log(cat instanceof Animal); //输出 true
//上面这两句可以看书,cat 并不属于Cat的实例对象,而只是Animal父类的实例对象
//总结
/*实例继承法的特点分析
优点:
1.不限制调用方式
确定:
1.实例是父类的实例,并不是子类的实例(这里好像违反了继承的理念,就好像小花猫属于动物,却不属于猫类一样)
2.不支持多继承
优点: 1.不限制调用方式
确定: 1.实例是父类的实例,并不是子类的实例(这里好像违反了继承的理念,就好像小花猫属于动物,却不属于猫类一样) 2.不支持多继承
第四种法法:组合继承法
/首先定义一个父类
function Animal(name,age){
//定义父类的属性
this.name = name || "Animal";
this.age = age ;
//定义父类的方法
this.sleep = function(){
console.log("这只"+this.name+"正在睡觉!");
};
this.showAge = function(){
console.log("这只"+this.name+"的年龄是"+this.age+"岁!");
}
};
//为父类添加原型方法
Animal.prototype.eat =function(food){
console.log("这只"+this.name+"正在吃"+food+"!")
}
Animal.prototype.weight = 10;
Animal.prototype.bark = function(){
console.log("bark");
}
//Javascript 实现继承的方法五 :
//组合继承法 核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
function Cat(name,age){
Animal.call(this);
this.name = name;
this.age = age;
this.bark = function(){
console.log("喵喵");
}
};
Cat.prototype = new Animal();
//测试代码
var cat = new Cat("猫",3);
console.log(cat.name); //猫
console.log(cat.age); //
console.log(cat.weight); //
cat.showAge(); // 这只猫的年龄是3岁
cat.eat("鱼"); // 这只猫正在吃鱼
cat.sleep(); // 这只猫正在睡觉
cat.bark(); // 喵喵
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
//从上面两行的输出结果来看,cat 是 父类 Animal 的 实例 ,也是子类Cat 的 实例
组合继承法实现继承的特点分析
优点: 1.弥补了构造函数法的缺陷,可以继承实例属性和方法,也可以继承原型属性和方法 2.既是子类的实例,也是父类的实例(比较符合继承的理念) 3.不存在引用属性共享问题 4.子类的实例对象可传参 5.函数可复用 缺点: 1.在生成子类实例对象的过程中,调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
结论 : 一般情况下,推荐使用这种方式的继承,缺点是多消耗一点内存
第五种方法:寄生组合继承法
//第六种,寄生组合继承法实现继承
//首先定义一个父类
function Animal(name,age){
//定义父类的属性
this.name = name || "Animal";
this.age = age ;
//定义父类的方法
this.sleep = function(){
console.log("这只"+this.name+"正在睡觉!");
};
this.showAge = function(){
console.log("这只"+this.name+"的年龄是"+this.age+"岁!");
}
};
//为父类添加原型方法
Animal.prototype.eat =function(food){
console.log("这只"+this.name+"正在吃"+food+"!")
}
Animal.prototype.weight = 10;
Animal.prototype.bark = function(){
console.log("bark");
}
//Javascript 实现继承的方法六 :
//寄生组合继承 通过寄生方式,砍掉父类的实例属性,
//这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
function Cat(name,age){
Animal.call(this);
this.name = name;
this.age = age ;
this.bark = function(){
console.log("喵喵");
}
};
//通过一个立即执行函数将父类的实例作为子类的原型
(function(){
//创建一个没有实例方法的类
var superClass = new Function; // 这里也可以写成,var sup = function(){}; 总之就是定义一个空构造函数
superClass.prototype = Animal.prototype;
//将实例作为子类的原型
Cat.prototype = new superClass();
})();
//测试代码
var cat = new Cat("猫",3);
console.log(cat.name); // 猫
console.log(cat.age); //
console.log(cat.weight); //
cat.showAge(); //这只猫的年龄是3岁!
cat.eat("鱼"); //这只猫正在吃鱼!
cat.sleep(); //这只猫正在睡觉!
cat.bark(); //喵喵
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
//上面两行可以看出,cat 是 子类 Cat 的实例对象, 也是 父类 Animal 的 实例对象
寄生组合继承法的特点分析
优点 : 1.集中了几种方法的优点,堪称完美
缺点 : 1.实现比较复杂
结论: 在实际项目和工程中,推荐使用这种方法
Javascript中,实现类与继承的方法和优缺点分析的更多相关文章
- JavaScript中的类式继承和原型式继承
最近在看<JavaScript设计模式>这本书,虽然内容比较晦涩,但是细品才发现此书内容的强大.刚看完第四章--继承,来做下笔记. 书中介绍了三种继承方式,类式继承.原型式继承和掺元类继承 ...
- ES6中。类与继承的方法,以及与ES5中的方法的对比
// 在ES5中,通常使用构造函数方法去实现类与继承 // 创建父类 function Father(name, age){ this.name = name; this.age = age; } F ...
- 【转】JavaScript中的原型和继承
请在此暂时忘记之前学到的面向对象的一切知识.这里只需要考虑赛车的情况.是的,就是赛车. 最近我正在观看 24 Hours of Le Mans ,这是法国流行的一项赛事.最快的车被称为 Le Mans ...
- JavaScript中的类
JavaScript类的相关知识 1.例子 /* 例1 */// 定义一个构造函数function Range(from, to){ this.from = from; this.to = ...
- Javascript中的类实现
Javascript本身并不支持面向对象,它没有访问控制符,它没有定义类的关键字class,它没有支持继承的extend或冒号,它也没有用来支持虚函数的virtual,不过,Javascript是一门 ...
- 谈谈javascript中的prototype与继承
谈谈javascript中的prototype与继承 今天想谈谈javascript中的prototype. 通常来说,javascript中的对象就是一个指向prototype的指针和一个自身的属性 ...
- JavaScript中定义类的方式详解
本文实例讲述了JavaScript中定义类的方式.分享给大家供大家参考,具体如下: Javascript本身并不支持面向对象,它没有访问控制符,它没有定义类的关键字class,它没有支持继承的exte ...
- C#类的继承,方法的重载和覆写
在网易云课堂上看到唐大仕老师讲解的关于类的继承.方法的重载和覆写的一段代码,注释比较详细,在此记下以加深理解. 小总结: 1.类的继承:允许的实例化方式:Student t=new Student() ...
- JavaScript中创建类,赋值给ajax中的data参数
缘由:因为要给根据是否选中checkbox来动态增加ajax中data的属性(ajax的data属性格式的几种方法,参考http://www.jb51.net/article/46676.htm) d ...
随机推荐
- restapi(1)- 文件上传下载服务
上次对restapi开了个头,设计了一个包括了身份验证和使用权限的restful服务开发框架.这是一个通用框架,开发人员只要直接往里面加新功能就行了.虽然这次的restapi是围绕着数据库表的CRUD ...
- dij模板
#include<cstdio> #include<vector> #include<queue> using namespace std; struct edge ...
- Socket 连接问题之大量 TIME_WAIT
简评:最近项目就出现了大量短连接导致建立新连接超时问题,最后是通过维护长连接解决的. 代理或者服务器设备都有端口限制,如果使用 TCP 连接,连接数量达到端口限制,在这种情况下,将不能创建新的连接. ...
- [LeetCode] 6. ZigZag Conversion (Medium)
原题链接 把字符串按照 ↓↗↓……的顺序,排列成一个 Z 形,返回 从左到右,按行读得的字符串. 思路: 建立一个二维数组来按行保存字符串. 按照 ↓↗↓……的方向进行对每一行加入字符. 太慢了这个解 ...
- random,time,sys,os
import random print(random.random()) #(0,1)大于0且小于1之间的小数 print(random.randint(1,3)) #大于等于1且小于等于3之间的整数 ...
- Cesium 学习(二)所支持的模型数据类型,以及转换
1.Cesium所支持的模型数据类型 目前所知的有glTF.glb.bgltf等格式的模型数据: 想要了解glTF等的知识可以看一下https://www.cnblogs.com/fuckgiser/ ...
- vue项目目录结构详解
项目简介基于 vue.js 的前端开发环境,用于前后端分离后的单页应用开发,可以在开发时使用 ES Next.scss 等最新语言特性.项目包含: 基础库: vue.js.vue-router.vue ...
- Java IO 为什么我们需要缓冲区
在执行IO操作我们通常会设置一个字节数组作为缓冲区用来写/读数据,一般情况下一个合理大小的缓冲区是有利于提升性能的,但是有一个问题一直困扰着我,为什么缓冲区可以提升IO操作的性能? 经查阅资料之后,总 ...
- XTTS系列之一:U2L迁移解决方案之XTTS的使用
本系列的定位是对XTTS及相关技术进行深入的学习研究.作为本系列的开篇,本着实用性的原则,我先把一次实际生产环境U2L的迁移实战实施方案进行提炼简化,旨在能清楚说明该如何使用XTTS这种解决方案来进行 ...
- python查漏补缺 --- 基础概念及控制结构
python 是一种面向对象的解释型计算机程序设计语言,在运行时由解释器处理,在执行程序之前不需要编译程序.Python就是一句话,写得快,跑得慢. 下面的内容是平时工作中容易忽略掉的小细节,希望借 ...