js的2种继承方式详解


Posted in Javascript onMarch 04, 2014

js中继承可以分为两种:对象冒充和原型链方式

一、对象冒充包括三种:临时属性方式、call()及apply()方式
1.临时属性方式

function Person(name){
     this.name = name;
     this.say = function(){
          alert('My name is '+this.name);
     }
}
function F2E(name,id){
     this.temp = Person;
     this.temp(name);
     delete this.temp;
     this.id = id;
     this.showId = function(){
          alert('Good morning,Sir,My work number is '+this.id);
     }
}
var simon = new F2E('Simon',9527);
simon.say();
simon.showId();

2.call()/apply()方式
实质上是改变了this指针的指向
function Person(name){
     this.name = name;
     this.say = function(){
          alert('My name is '+this.name);
     }
}
function F2E(name,id){
     Person.call(this,name); //apply()方式改成Person.apply(this,new Array(name));
     this.id = id;
     this.showId = function(){
          alert('Good morning,Sir,My work number is '+this.id);
     }
}
var simon = new F2E('Simon',9527);
simon.say();
simon.showId();

缺点:先来看这么一张内存分配图:

在OO概念中,new实例化后,对象就在堆内存中形成了自己的空间,值得注意的是,这个代码段。而成员方法就是存在这个代码段的,并且方法是共用的。问题就在这里,通过对象冒充方式继承时,所有的成员方法都是指向this的,也就是说new之后,每个实例将都会拥有这个成员方法,并不是共用的,这就造成了大量的内存浪费。并且通过对象冒充的方式,无法继承通过prototype方式定义的变量和方法,如以下代码将会出错:

function Person(name){
     this.name = name;
     this.say = function(){
          alert('My name is '+this.name);
     }
}
Person.prototype.age = 20;
Person.prototype.sayAge = function(){alert('My age is '+this.age)};function F2E(name,id){
     Person.apply(this,new Array(name));
     this.id = id;
     this.showId = function(){
          alert('Good morning,Sir,My work number is '+this.id);
     }
}
var simon = new F2E('Simon',9527);
simon.sayAge(); //提示TypeError: simon.sayAge is not a function

二、原型链方式
function Person(){
     this.name = 'Simon';
}
Person.prototype.say = function(){
     alert('My name is '+this.name);
}function F2E(id){
     this.id = id;
     this.showId = function(){
          alert('Good morning,Sir,My work number is '+this.id);
     }
}
F2E.prototype = new Person();
var simon = new F2E(9527);
simon.say();
simon.showId();
alert(simon.hasOwnProperty('id')); //检查是否为自身属性

接下来按照上面的例子来理解以下js原型链概念:

原型链可以理解成:js中每个对象均有一个隐藏的__proto__属性,一个实例化对象的__proto__属性指向其类的prototype方法,而这个prototype方法又可以被赋值成另一个实例化对象,这个对象的__proto__又需要指向其类,由此形成一条链,也就是前面代码中的

F2E.prototype = new Person()

这句是关键。js对象在读取某个属性时,会先查找自身属性,没有则再去依次查找原型链上对象的属性。也就是说原型链的方法是可以共用的,这样就解决了对象冒充浪费内存的缺点。

下面再来说缺点:
缺点显而易见,原型链方式继承,就是实例化子类时不能将参数传给父类,也就是为什么这个例子中function Person()没有参数,而是直接写成了this.name=”Simon”的原因。下面的代码将不能达到预期的效果:

function Person(name){
     this.name = name;
}
Person.prototype.say = function(){
     alert('My name is '+this.name);
}function F2E(name,id){
     this.id = id;
     this.showId = function(){
          alert('Good morning,Sir,My work number is '+this.id);
     }
}
F2E.prototype = new Person();
var simon = new F2E("Simon",9527);
simon.say();
simon.showId();
 
function Person(name){
     this.name = name;
}
Person.prototype.say = function(){
     alert('My name is '+this.name);
}
function F2E(name,id){
     this.id = id;
     this.showId = function(){
          alert('Good morning,Sir,My work number is '+this.id);
     }
}
F2E.prototype = new Person();  //此处无法进行传值,this.name或者name都不行,直接写F2E.prototype = new Person('wood')是可以的,但是这样的话simon.say()就变成了My name is wood
var simon = new F2E("Simon",9527);
simon.say();  //弹出 My name is undefined
simon.showId();

最后,总结一下自认为较好的继承实现方式,成员变量采用对象冒充方式,成员方法采用原型链方式,代码如下:

function Person(name){
     this.name = name;
}Person.prototype.say = function(){
     alert('My name is '+this.name);
}
function F2E(name,id){
     Person.call(this,name);
     this.id = id;
}
F2E.prototype = new Person(); 
//此处注意一个细节,showId不能写在F2E.prototype = new Person();前面
F2E.prototype.showId = function(){
     alert('Good morning,Sir,My work number is '+this.id);
}
var simon = new F2E("Simon",9527);
simon.say();
simon.showId();
Javascript 相关文章推荐
js实现简单登录功能的实例代码
Nov 09 Javascript
node.js中的buffer.toJSON方法使用说明
Dec 14 Javascript
jQuery使用before()和after()在元素前后添加内容的方法
Mar 26 Javascript
JavaScript合并两个数组并去除重复项的方法
Jun 13 Javascript
JavaScript中的this,call,apply使用及区别详解
Jan 29 Javascript
如何解决手机浏览器页面点击不跳转浏览器双击放大网页
Jul 01 Javascript
完全深入学习Bootstrap表单
Nov 28 Javascript
EasyUI学习之Combobox下拉列表(1)
Dec 29 Javascript
JS实现左边列表移到到右边列表功能
Mar 28 Javascript
ES6学习笔记之字符串、数组、对象、函数新增知识点实例分析
Jan 22 Javascript
vscode+gulp轻松开发小程序的完整步骤
Oct 18 Javascript
html+vue.js 实现漂亮分页功能可兼容IE
Nov 07 Javascript
Seajs的学习笔记
Mar 04 #Javascript
文本域中换行符的替换示例
Mar 04 #Javascript
为jquery的ajaxfileupload增加附加参数的方法
Mar 04 #Javascript
Document.location.href和.replace的区别示例介绍
Mar 04 #Javascript
LABjs、RequireJS、SeaJS的区别
Mar 04 #Javascript
js的Boolean对象初始值示例
Mar 04 #Javascript
js动态拼接正则表达式的两种方法
Mar 04 #Javascript
You might like
php获取是星期几的的一些常用姿势
2019/12/15 PHP
gearman中任务的优先级和返回状态实例分析
2020/02/27 PHP
Thinkphp框架使用list_to_tree 实现无限级分类列出所有节点示例
2020/04/04 PHP
JS无限极树形菜单,json格式、数组格式通用示例
2013/07/30 Javascript
JS二维数组的定义说明
2014/03/03 Javascript
jQuery实现的在线答题功能
2015/04/12 Javascript
浅谈jquery事件处理
2015/04/24 Javascript
Jquery 自定义事件实现发布/订阅的简单实例
2016/06/12 Javascript
HTML5 实现的一个俄罗斯方块实例代码
2016/09/19 Javascript
js窗口震动小程序分享
2016/11/28 Javascript
Vue.js原理分析之observer模块详解
2017/02/17 Javascript
用Vue-cli搭建的项目中引入css报错的原因分析
2017/07/20 Javascript
ES6解构赋值实例详解
2017/10/31 Javascript
vuex 项目结构目录及一些简单配置介绍
2018/04/08 Javascript
JS实现对json对象排序并删除id相同项功能示例
2018/04/18 Javascript
如何在JavaScript中谨慎使用代码注释
2019/06/21 Javascript
[50:05]VGJ.S vs OG 2018国际邀请赛淘汰赛BO3 第二场 8.22
2018/08/23 DOTA
[32:07]完美世界DOTA2联赛PWL S3 LBZS vs Rebirth 第一场 12.16
2020/12/17 DOTA
Python文件操作类操作实例详解
2014/07/11 Python
K-近邻算法的python实现代码分享
2017/12/09 Python
Python基于csv模块实现读取与写入csv数据的方法
2018/01/18 Python
pandas string转dataframe的方法
2018/04/11 Python
用python实现将数组元素按从小到大的顺序排列方法
2018/07/02 Python
Python基础之循环语句用法示例【for、while循环】
2019/03/23 Python
python实现Oracle查询分组的方法示例
2020/04/30 Python
软件测试常见笔试题
2012/02/04 面试题
后勤自我鉴定
2013/10/13 职场文书
夜大毕业生自我评价分享
2013/11/10 职场文书
给同事的道歉信
2014/01/11 职场文书
大学生优秀自荐信范文
2014/02/25 职场文书
2015年上半年物业工作总结
2015/03/30 职场文书
2015年销售工作总结范文
2015/03/30 职场文书
世界名著读书笔记
2015/06/25 职场文书
2016年共产党员公开承诺书
2016/03/24 职场文书
漫画《尖帽子的魔法工坊》宣布动画化
2022/04/06 日漫
Java 垃圾回收超详细讲解记忆集和卡表
2022/04/08 Java/Android