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 相关文章推荐
javascript提取URL的搜索字符串中的参数(自定义函数实现)
Jan 22 Javascript
javascript用户注册提示效果的简单实例
Aug 17 Javascript
jquery 使用简明教程
Mar 05 Javascript
使用Raygun对Node.js应用进行错误处理的方法
Jun 23 Javascript
通过js获取上传的图片信息(临时保存路径,名称,大小)然后通过ajax传递给后端的方法
Oct 01 Javascript
javascript针对不确定函数的执行方法
Dec 16 Javascript
BootStrap Datetimepicker 汉化的实现代码
Feb 10 Javascript
JS基于onclick事件实现单个按钮的编辑与保存功能示例
Feb 13 Javascript
微信小程序 页面传值详解
Mar 10 Javascript
详解关于Angular4 ng-zorro使用过程中遇到的问题
Dec 05 Javascript
微信小程序视图控件与bindtap之间的问题的解决
Apr 08 Javascript
VUE接入腾讯验证码功能(滑块验证)备忘
May 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
Discuz7.2版的faq.php SQL注入漏洞分析
2014/08/06 PHP
php parse_str() 函数的定义和用法
2016/05/23 PHP
多浏览器兼容的获取元素和鼠标的位置的js代码
2009/12/15 Javascript
基于jquery的使ListNav兼容中文首字拼音排序的实现代码
2011/07/10 Javascript
Javascript中3种实现继承的方法和代码实例
2014/08/12 Javascript
node.js中的events.emitter.removeListener方法使用说明
2014/12/10 Javascript
JavaScript模拟深蓝vs卡斯帕罗夫的国际象棋对局示例
2015/04/22 Javascript
详解JavaScript的Date对象(制作简易钟表)
2020/04/07 Javascript
vue2中filter()的实现代码
2017/07/09 Javascript
老生常谈js中的MVC
2017/07/25 Javascript
详解angular部署到iis出现404解决方案
2018/08/14 Javascript
layui多图上传实现删除功能的例子
2019/09/23 Javascript
Python实现冒泡,插入,选择排序简单实例
2014/08/18 Python
python数据结构之图的实现方法
2015/07/08 Python
浅谈Python类的__getitem__和__setitem__特殊方法
2016/12/25 Python
windows下安装Python的XlsxWriter模块方法
2018/05/03 Python
django使用haystack调用Elasticsearch实现索引搜索
2019/07/24 Python
Python 从subprocess运行的子进程中实时获取输出的例子
2019/08/14 Python
python实现宿舍管理系统
2019/11/22 Python
浅谈python3 构造函数和析构函数
2020/03/12 Python
python 如何上传包到pypi
2020/12/24 Python
最受欢迎的自我评价
2013/12/22 职场文书
开展党的群众路线教育实践活动方案
2014/02/05 职场文书
争论的故事教学反思
2014/02/06 职场文书
酒店行政人事部经理职务说明书
2014/02/26 职场文书
《真想变成大大的荷叶》教学反思
2014/04/14 职场文书
竞选学生会主席演讲稿
2014/04/24 职场文书
小学生运动会通讯稿
2014/09/23 职场文书
党员四风自我剖析材料
2014/10/07 职场文书
2014七年级班主任工作总结
2014/12/05 职场文书
2015年招商引资工作总结
2015/04/25 职场文书
2015初中政治教学工作总结
2015/07/21 职场文书
三十年同学聚会感言
2015/07/30 职场文书
Linux7.6二进制安装Mysql8.0.27详细操作步骤
2021/11/27 MySQL
mysql sql常用语句大全
2022/06/21 MySQL
HttpClient实现表单提交上传文件
2022/08/14 Java/Android