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 相关文章推荐
关于URL中的特殊符号使用介绍
Nov 03 Javascript
简约JS日历控件 实例代码
Jul 12 Javascript
jquery清空表单数据示例分享
Feb 13 Javascript
js限制文本框只能输入整数或者带小数点的数字
Apr 27 Javascript
JavaScript使用正则表达式获取全部分组内容的方法示例
Jan 17 Javascript
JS将unicode码转中文方法
May 08 Javascript
详解在微信小程序的JS脚本中使用Promise来优化函数处理
Mar 06 Javascript
js module大战
Apr 19 Javascript
JavaScript面向对象编程小游戏---贪吃蛇代码实例
May 15 Javascript
JS写滑稽笑脸运动效果
May 28 Javascript
ES6 Symbol在对象中的作用实例分析
Jun 06 Javascript
js利用拖放实现添加删除
Aug 27 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
jquery ui dialog ie8出现滚动条的解决方法
2010/12/06 Javascript
JavaScript对象和字串之间的转换实例探讨
2013/04/21 Javascript
setTimeout和setInterval的深入理解
2013/11/08 Javascript
angularjs实现与服务器交互分享
2014/06/24 Javascript
JavaScript常用脚本汇总(三)
2015/03/04 Javascript
JS实现可点击展开与关闭的左侧广告代码
2015/09/02 Javascript
jQuery中用on绑定事件时需注意的事项
2017/03/19 Javascript
详细分析jsonp的原理和实现方式
2017/11/20 Javascript
JQuery 又谈ajax局部刷新
2017/11/27 jQuery
JavaScript面试出现频繁的一些易错点整理
2018/03/29 Javascript
如何编写一个d.ts文件的步骤详解
2018/04/13 Javascript
如何利用@angular/cli V6.0直接开发PWA应用详解
2018/05/06 Javascript
nuxt中使用路由守卫的方法步骤
2019/01/27 Javascript
少女风vue组件库的制作全过程
2019/05/15 Javascript
微信小程序select下拉框实现效果
2019/05/15 Javascript
JS自定义对象创建与简单使用方法示例
2020/01/15 Javascript
vue-resourc发起异步请求的方法
2020/02/11 Javascript
vue cli3.0打包上线静态资源找不到路径的解决操作
2020/08/03 Javascript
[02:03]《现实生活中的DOTA2》—林书豪&DOTA2职业选手出演短片
2015/08/18 DOTA
python 实时遍历日志文件
2016/04/12 Python
Django开发中的日志输出的方法
2018/07/02 Python
OpenCV2从摄像头获取帧并写入视频文件的方法
2018/08/03 Python
python高效过滤出文件夹下指定文件名结尾的文件实例
2018/10/21 Python
使用Python为中秋节绘制一块美味的月饼
2019/09/11 Python
python 消费 kafka 数据教程
2019/12/21 Python
python定义类的简单用法
2020/07/24 Python
html5 标签
2009/07/16 HTML / CSS
德国团购网站:Groupon德国
2018/03/13 全球购物
阿根廷在线宠物商店:Puppis
2018/03/23 全球购物
SQL面试题
2013/12/09 面试题
Weblogic和WebSphere不同特点
2012/05/09 面试题
给男朋友的道歉信
2014/01/12 职场文书
个人查摆问题整改措施
2014/10/04 职场文书
中班上学期个人总结
2015/02/12 职场文书
厉害!这是Redis可视化工具最全的横向评测
2021/07/15 Redis
Redis超详细讲解高可用主从复制基础与哨兵模式方案
2022/04/07 Redis