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初学者需要了解10个小技巧
Aug 25 Javascript
JS随机生成不重复数据的实例方法
Jul 17 Javascript
jQuery中slice()方法用法实例
Jan 07 Javascript
JavaScript获取当前cpu使用率的方法
Dec 15 Javascript
原生js代码实现图片放大境效果
Oct 30 Javascript
jQuery实现简单漂亮的Nav导航菜单效果
Mar 29 jQuery
详解vue-router基本使用
Apr 18 Javascript
写给小白看的JavaScript异步
Nov 29 Javascript
JavaScript设计模式之单例模式原理与用法实例分析
Jul 26 Javascript
JS 实现微信扫一扫功能
Sep 14 Javascript
js实现随机点名功能
Dec 23 Javascript
vue+element UI实现树形表格
Dec 29 Vue.js
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
Apache2 httpd.conf 中文版
2006/11/17 PHP
通过缓存数据库结果提高PHP性能的原理介绍
2012/09/05 PHP
使用php+apc实现上传进度条且在IE7下不显示的问题解决方法
2013/04/25 PHP
PHP调用C#开发的dll类库方法
2014/07/28 PHP
ThinkPHP中公共函数路径和配置项路径的映射分析
2014/11/22 PHP
三种检测iPhone/iPad设备方向的方法
2014/04/23 Javascript
原生javascript实现的一个简单动画效果
2016/03/30 Javascript
JavaScript比较当前时间是否在指定时间段内的方法
2016/08/02 Javascript
JS 实现 ajax 异步浏览器兼容问题
2017/01/21 Javascript
微信小程序 列表的上拉加载和下拉刷新的实现
2017/04/01 Javascript
Angular2数据绑定详解
2017/04/18 Javascript
ES6下React组件的写法示例代码
2017/05/04 Javascript
Angular实现响应式表单
2017/08/04 Javascript
Vue中util的工具函数实例详解
2019/07/08 Javascript
vue框架制作购物车小球动画效果实例代码
2019/09/26 Javascript
基于JavaScript实现十五拼图代码实例
2020/04/26 Javascript
js+cavans实现图片滑块验证
2020/09/29 Javascript
Echarts在Taro微信小程序开发中的踩坑记录
2020/11/09 Javascript
[42:35]2018DOTA2亚洲邀请赛3月30日 小组赛A组 VG VS OpTic
2018/03/31 DOTA
python基于urllib实现按照百度音乐分类下载mp3的方法
2015/05/25 Python
matplotlib简介,安装和简单实例代码
2017/12/26 Python
使用实现XlsxWriter创建Excel文件并编辑
2018/05/04 Python
解决pycharm界面不能显示中文的问题
2018/05/23 Python
用Python编写一个高效的端口扫描器的方法
2018/12/20 Python
详解Python3定时器任务代码
2019/09/23 Python
X/HTML5 和 XHTML2
2008/10/17 HTML / CSS
银河香水:Galaxy Perfume
2019/03/25 全球购物
基层工作经历证明
2014/01/13 职场文书
体育教师自我鉴定
2014/02/12 职场文书
《一个小村庄的故事》教学反思
2014/04/13 职场文书
协议书模板
2014/04/23 职场文书
党的群众路线教育实践活动个人对照检查材料(医生)
2014/11/05 职场文书
2014年党支部工作总结
2014/11/13 职场文书
幼儿学前班评语
2014/12/29 职场文书
高温慰问简报
2015/07/21 职场文书
python缺失值填充方法示例代码
2022/12/24 Python