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运行机制之事件循环(Event Loop)详解
Oct 10 Javascript
轻松学习Javascript闭包函数
Dec 15 Javascript
基于JavaScript实现移除(删除)数组中指定元素
Jan 04 Javascript
简介AngularJS中$http服务的用法
Feb 06 Javascript
js制作网站首页图片轮播特效代码
Aug 30 Javascript
前端 Vue.js 和 MVVM 详细介绍
Dec 29 Javascript
touch.js 拖动、缩放、旋转 (鼠标手势)功能代码
Feb 04 Javascript
JavaScript数据结构之链表的实现
Mar 19 Javascript
vue-cli中的babel配置文件.babelrc实例详解
Feb 22 Javascript
vue+vuex+axios实现登录、注册页权限拦截
Mar 09 Javascript
angular使用md5,CryptoJS des加密的方法
Jun 03 Javascript
js中比较两个对象是否相同的方法示例
Sep 02 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
Protoss兵种介绍
2020/03/14 星际争霸
使用PHP curl模拟浏览器抓取网站信息
2013/10/28 PHP
php递归法读取目录及文件的方法
2015/01/30 PHP
php 中htmlentities导致中文无法查询问题
2018/09/10 PHP
CentOS7.0下安装PHP5.6.30服务的教程详解
2018/09/29 PHP
php封装实现钉钉机器人报警接口的示例代码
2020/08/08 PHP
科讯商业版中用到的ajax空间与分页函数
2007/09/02 Javascript
js解析与序列化json数据(一)json.stringify()的基本用法
2013/02/01 Javascript
JavaScript排序算法之希尔排序的2个实例
2014/04/04 Javascript
JavaScript编写连连看小游戏
2015/07/07 Javascript
javascript cookie基础应用之记录用户名的方法
2016/09/20 Javascript
js实现导航栏中英文切换效果
2017/01/16 Javascript
js学习总结之DOM2兼容处理重复问题的解决方法
2017/07/27 Javascript
pace.js和NProgress.js两个加载进度插件的一点小总结
2018/01/31 Javascript
解决低版本的浏览器不支持es6的import问题
2018/03/09 Javascript
Vue隐藏显示、只读实例代码
2018/07/18 Javascript
vue服务端渲染添加缓存的方法
2018/09/18 Javascript
详解vue2.0 资源文件assets和static的区别
2018/11/27 Javascript
javascript二维数组和对象的深拷贝与浅拷贝实例分析
2019/10/26 Javascript
js函数柯里化的方法和作用实例分析
2020/04/11 Javascript
解决VUE项目localhost端口服务器拒绝连接,只能用127.0.0.1的问题
2020/08/14 Javascript
js数组的基本使用总结
2021/01/18 Javascript
Python openpyxl 遍历所有sheet 查找特定字符串的方法
2018/12/10 Python
python通过tcp发送xml报文的方法
2018/12/28 Python
Python使用pyenv实现多环境管理
2021/02/05 Python
python实现图片转字符画的完整代码
2021/02/21 Python
使用CSS3设计地图上的雷达定位提示效果
2016/04/05 HTML / CSS
瑞士网球商店:Tennis-Point
2020/03/12 全球购物
简单而又朴实的个人求职信分享
2013/12/12 职场文书
明信片寄语大全
2014/04/08 职场文书
2014财产信托协议书范本
2014/11/18 职场文书
统计员岗位职责范本
2015/04/14 职场文书
酒店前台岗位职责
2015/04/16 职场文书
2019年家电促销广告语集锦
2019/10/21 职场文书
浅析InnoDB索引结构
2021/04/05 MySQL
Spring中bean的生命周期之getSingleton方法
2021/06/30 Java/Android