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 相关文章推荐
window.addEventListener来解决让一个js事件执行多个函数
Dec 26 Javascript
javascript动态的改变IFrame的高度实现自动伸展
Oct 12 Javascript
JavaScript自定义等待wait函数实例分析
Mar 23 Javascript
深入浅析JavaScript中对事件的三种监听方式
Sep 29 Javascript
浅析JavaScriptSerializer类的序列化与反序列化
Nov 22 Javascript
JS实现网页抢购功能(触发,终止脚本)
Nov 27 Javascript
利用10行js代码实现上下滚动公告效果
Dec 08 Javascript
jQuery获取所有父级元素及同级元素及子元素的方法(推荐)
Jan 21 jQuery
详解Puppeteer 入门教程
May 09 Javascript
webpack4 处理CSS的方法示例
Sep 03 Javascript
JavaScript寄生组合式继承原理与用法分析
Jan 11 Javascript
如何使用pm2快速将项目部署到远程服务器
Mar 12 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解析html的实现代码
2011/08/08 PHP
php 阴历-农历-转换类代码
2012/01/16 PHP
PHP语法自动检查的Vim插件
2014/08/11 PHP
yii2.0之GridView自定义按钮和链接用法
2014/12/15 PHP
基于OpenCart 开发支付宝,财付通,微信支付参数错误问题
2015/10/01 PHP
总结的一些PHP开发中的tips(必看篇)
2017/03/24 PHP
微信公众平台开发教程④ ThinkPHP框架下微信支付功能图文详解
2019/04/10 PHP
Javascript注入技巧
2007/06/22 Javascript
快速排序 php与javascript的不同之处
2011/02/22 Javascript
JS实现可拖曳、可关闭的弹窗效果
2015/09/26 Javascript
Struts2+jquery.form.js实现图片与文件上传的方法
2016/05/05 Javascript
JavaScript实现图片懒加载(Lazyload)
2016/11/28 Javascript
javascript添加前置0(补零)的几种方法
2017/01/05 Javascript
BootStrap table删除指定行的注意事项(笔记整理)
2017/02/05 Javascript
JavaScript数组迭代方法
2017/03/03 Javascript
nodejs获取微信小程序带参数二维码实现代码
2017/04/12 NodeJs
vue引入ueditor及node后台配置详解
2018/01/03 Javascript
react-native 圆弧拖动进度条实现的示例代码
2018/04/12 Javascript
浅谈mvvm-simple双向绑定简单实现
2018/04/18 Javascript
vue-cli中vue本地实现跨域调试接口
2019/01/16 Javascript
Vue Router的手写实现方法实现
2020/03/02 Javascript
[01:47]2018年度DOTA2最具人气解说-完美盛典
2018/12/16 DOTA
[43:26]完美世界DOTA2联赛PWL S2 Forest vs Rebirth 第二场 11.20
2020/11/23 DOTA
Python实现将DOC文档转换为PDF的方法
2015/07/25 Python
一条命令解决mac版本python IDLE不能输入中文问题
2018/05/15 Python
连接pandas以及数组转pandas的方法
2019/06/28 Python
python画图常规设置方式
2020/03/05 Python
在Python IDLE 下调用anaconda中的库教程
2020/03/09 Python
python爬虫scrapy基于CrawlSpider类的全站数据爬取示例解析
2021/02/20 Python
HTML5 Canvas中使用路径描画二阶、三阶贝塞尔曲线
2015/01/01 HTML / CSS
解析html5 canvas实现背景鼠标连线动态效果代码
2019/06/17 HTML / CSS
俄罗斯品牌服装和鞋子在线商店:BRIONITY
2020/03/26 全球购物
鸡毛信观后感
2015/06/11 职场文书
2016春节放假通知范文
2015/08/18 职场文书
MySQL实例精讲单行函数以及字符数学日期流程控制
2021/10/15 MySQL
Java 使用类型为Object的变量指向任意类型的对象
2022/04/13 Java/Android