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 相关文章推荐
网页中实现浏览器的最大,最小化和关闭按钮
Mar 12 Javascript
jquery 打开窗口返回值实现代码
Mar 04 Javascript
JS方法调用括号的问题探讨
Jan 24 Javascript
Seajs的学习笔记
Mar 04 Javascript
JavaScript拆分字符串时产生空字符的解决方案
Sep 26 Javascript
jQuery实现高亮显示的方法
Mar 10 Javascript
数据结构中的各种排序方法小结(JS实现)
Jul 23 Javascript
jQuery ajax MD5实现用户注册即时验证功能
Oct 11 Javascript
Angularjs单选改为多选的开发过程及问题解析
Feb 17 Javascript
微信小程序云开发详细教程
May 16 Javascript
微信小程序 下拉刷新及上拉加载原理解析
Nov 06 Javascript
JavaScript实现跟随鼠标移动的盒子
Jan 28 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 iconv() : Detected an illegal character in input string
2010/12/05 PHP
解析php防止form重复提交的方法
2013/07/01 PHP
php中AES加密解密的例子小结
2014/02/18 PHP
几个优化WordPress中JavaScript加载体验的插件介绍
2015/12/17 PHP
PHP无限极分类函数的实现方法详解
2017/04/15 PHP
转一个日期输入控件,支持FF
2007/04/27 Javascript
javascript removeChild 使用注意事项
2009/04/11 Javascript
基于jquery的仿百度的鼠标移入图片抖动效果
2010/09/17 Javascript
网页源代码保护(禁止右键、复制、另存为、查看源文件)
2012/05/23 Javascript
js中使用replace方法完成某个字符的转换
2014/08/20 Javascript
jquery隔行换色效果实现方法
2015/01/15 Javascript
如何用angularjs制作一个完整的表格
2016/01/21 Javascript
基于slideout.js实现移动端侧边栏滑动特效
2016/11/28 Javascript
AngularJS中$apply方法和$watch方法用法总结
2016/12/13 Javascript
解决option标签selected="selected"属性失效的问题
2017/11/06 Javascript
10个最受欢迎的 JavaScript框架(推荐)
2019/04/24 Javascript
微信小程序自定义组件实现环形进度条
2020/11/17 Javascript
[05:35]DOTA2英雄梦之声_第13期_拉比克
2014/06/21 DOTA
Python模块学习 re 正则表达式
2011/05/19 Python
Python中对元组和列表按条件进行排序的方法示例
2015/11/10 Python
python开启debug模式的方法
2019/06/27 Python
详解CSS3中使用gradient实现渐变效果的方法
2015/08/18 HTML / CSS
HTML5: Web 标准最巨大的飞跃
2008/10/17 HTML / CSS
描述一下JVM加载class文件的原理机制
2013/12/08 面试题
货代行业个人求职简历的自我评价
2013/10/22 职场文书
财务主管自我鉴定
2014/01/17 职场文书
青年志愿者事迹材料
2014/02/07 职场文书
篮球社团活动总结
2014/06/27 职场文书
英语专业求职信
2014/07/08 职场文书
解除劳动合同协议书范本
2014/09/13 职场文书
学校领导班子对照检查材料
2014/09/24 职场文书
2014年高中生自我评价范文
2014/09/26 职场文书
2019最新校园运动会广播稿!
2019/06/28 职场文书
导游词创作书写原则以及开场白技巧怎么学?
2019/09/25 职场文书
SQL实战演练之网上商城数据库商品类别数据操作
2021/10/24 MySQL
python 管理系统实现mysql交互的示例代码
2021/12/06 Python