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 相关文章推荐
关于二级域名下使用一级域名下的COOKIE的问题
Nov 07 Javascript
jquery实现简单易懂的图片展示小例子
Nov 21 Javascript
js中实现多态采用和继承类似的方法
Aug 22 Javascript
jQuery Mobile弹出窗、弹出层知识汇总
Jan 05 Javascript
javascript实现图片轮播效果
Jan 20 Javascript
谷歌showModalDialog()方法不兼容出现对话窗口的解决办法
Feb 15 Javascript
JavaScript代码生成PDF文件的方法
Feb 26 Javascript
javascript鼠标滑过显示二级菜单特效
Nov 18 Javascript
ES6扩展运算符的用途实例详解
Aug 20 Javascript
Vue中computed与methods的区别详解
Mar 24 Javascript
Nuxt配合Node在实际生产中的应用详解
Aug 07 Javascript
JS如何寻找数组中心索引过程解析
Jun 01 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
ECSHOP完美解决Deprecated: preg_replace()报错的问题
2016/05/17 PHP
php使用Jpgraph创建3D饼形图效果示例
2017/02/15 PHP
flash 得到自身url参数的代码
2009/11/15 Javascript
javascript标签在页面中的位置探讨
2013/04/11 Javascript
js和css写一个可以自动隐藏的悬浮框
2014/03/05 Javascript
jQuery前端分页示例分享
2015/02/10 Javascript
javascript的BOM汇总
2015/07/16 Javascript
JS+CSS实现电子商务网站导航模板效果代码
2015/09/10 Javascript
JavaScript代码实现禁止右键、禁选择、禁粘贴、禁shift、禁ctrl、禁alt
2015/11/17 Javascript
AngularJS转换响应内容
2016/01/27 Javascript
深入理解JavaScript单体内置对象
2016/06/06 Javascript
js实现图片切换(动画版)
2016/12/25 Javascript
canvas雪花效果核心代码分享
2017/02/19 Javascript
浅谈react+es6+webpack的基础配置
2017/08/09 Javascript
vue不通过路由直接获取url中参数的方法示例
2017/08/24 Javascript
vue获取input输入值的问题解决办法
2017/10/17 Javascript
Angular4编程之表单响应功能示例
2017/12/13 Javascript
基于 flexible 的 Vue 组件:Toast -- 显示框效果
2017/12/26 Javascript
JS栈stack类的实现与使用方法示例
2019/01/31 Javascript
prettier自动格式化去换行的实现代码
2020/08/25 Javascript
如何利用node转发请求详解
2020/09/17 Javascript
微信小程序开发数据缓存基础知识辨析及运用实例详解
2020/11/06 Javascript
three.js中多线程的使用及性能测试详解
2021/01/07 Javascript
python 实现网上商城,转账,存取款等功能的信用卡系统
2016/07/15 Python
如何利用Python模拟GitHub登录详解
2019/07/15 Python
css3绘制百度的小度熊
2018/10/29 HTML / CSS
让IE下支持Html5的placeholder属性的插件
2014/09/02 HTML / CSS
高中的自我鉴定
2013/12/16 职场文书
关于雷锋的演讲稿
2014/05/10 职场文书
党员四风问题对照检查材料思想汇报
2014/09/16 职场文书
个人政风行风自查自纠报告
2014/10/21 职场文书
个人求职信格式范文
2015/03/20 职场文书
小学生节水倡议书
2015/04/29 职场文书
培训讲师开场白
2015/06/01 职场文书
总结高并发下Nginx性能如何优化
2021/11/01 Servers
MySQL中EXPLAIN语句及用法
2022/05/20 MySQL