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 parseInt 函数分析(转)
Mar 21 Javascript
响应鼠标变换表格背景或者颜色的代码
Mar 30 Javascript
javascript 打开页面window.location和window.open的区别
Mar 17 Javascript
详谈JavaScript 匿名函数及闭包
Nov 14 Javascript
window.location.hash知识汇总
Nov 09 Javascript
Kindeditor在线文本编辑器如何过滤HTML
Apr 14 Javascript
Vue自定义事件(详解)
Aug 19 Javascript
jquery插件开发之选项卡制作详解
Aug 30 jQuery
Vue与Node.js通过socket.io通信的示例代码
Jul 25 Javascript
jQuery实现基本淡入淡出效果的方法详解
Sep 05 jQuery
原生JS使用Canvas实现拖拽式绘图功能
Jun 05 Javascript
vue-cli设置publicPath小记
Apr 14 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图像处理之使用imagecolorallocate()函数设置颜色例子
2014/11/19 PHP
php动态生成版权所有信息的方法
2015/03/24 PHP
mac下多个php版本快速切换的方法
2016/10/09 PHP
微信公众平台开发-微信服务器IP接口实例(含源码)
2017/03/05 PHP
表单提交验证类
2006/07/14 Javascript
3kb jQuery代码搞定各种树形选择的实现方法
2016/06/10 Javascript
javascript使用闭包模拟对象的私有属性和方法
2016/10/05 Javascript
Bootstrap CSS布局之表格
2016/12/17 Javascript
Html5 js实现手风琴效果
2020/04/17 Javascript
基于bootstrap实现收缩导航条
2017/03/17 Javascript
vue实现todolist单页面应用
2017/04/11 Javascript
Javascript实现倒计时时差效果
2017/05/18 Javascript
JavaScript中如何判断一个值的类型
2017/09/15 Javascript
vue如何进行动画的封装
2018/09/26 Javascript
详解vue-cli+element-ui树形表格(多级表格折腾小计)
2019/04/17 Javascript
使用Python的Tornado框架实现一个简单的WebQQ机器人
2015/04/24 Python
Python实现PS滤镜特效Marble Filter玻璃条纹扭曲效果示例
2018/01/29 Python
对python中list的拷贝与numpy的array的拷贝详解
2019/01/29 Python
Python面向对象思想与应用入门教程【类与对象】
2019/04/12 Python
python抓取需要扫微信登陆页面
2019/04/29 Python
python实现网站微信登录的示例代码
2019/09/18 Python
在OpenCV里实现条码区域识别的方法示例
2019/12/04 Python
tensorflow2.0与tensorflow1.0的性能区别介绍
2020/02/07 Python
Python递归求出列表(包括列表中的子列表)的最大值实例
2020/02/27 Python
使用Python绘制台风轨迹图的示例代码
2020/09/21 Python
python wsgiref源码解析
2021/02/06 Python
Notino瑞典:购买香水和美容产品
2019/07/26 全球购物
Diptyque英国官方网站:源自法国的知名香氛品牌
2019/08/28 全球购物
如何将字串String转换成整数int
2015/02/21 面试题
创业计划书如何吸引他人眼球
2014/01/10 职场文书
人力资源部经理助理岗位职责
2014/03/04 职场文书
驾驶员培训方案
2014/05/01 职场文书
银行贷款收入证明
2014/10/17 职场文书
2014年村计划生育工作总结
2014/11/14 职场文书
上手简单,功能强大的Python爬虫框架——feapder
2021/04/27 Python
优化Mysql查询的示例
2022/04/26 MySQL