JavaScript实现继承的方式和各自的优缺点
ECMAscript只支持实现继承,主要是依靠原型链来实现的。
JavaScript实现继承的方式:
- 类式继承
- 构造函数继承
- 组合继承
- 寄生组合式继承
1.类式继承
//类式继承
//声明父类
function Animal(color) {
this.name = 'animal';
this.type = ['pig', 'cat'];
this.color = color;
}
// 为父类添加共有方法
Animal.prototype.greet = function(sound) {
console.log(sound);
} //声明子类
function Dog(){
this.name = 'dog';
} //类式继承父类(父类实例作为子类的原型对象)
Dog.prototype = new Animal('white'); //子类实例继承父类的属性和方法
var dog1 = new Dog();
console.log(dog1.name); //dog
console.log(dog1.type); //[ 'pig', 'cat' ]
dog1.greet('wangwangwang'); //'wangwangwang' //缺陷1:修改子类实例对象继承自父类的属性或方法时,会影响新创建的子类实例
dog1.type.push('dog');
var dog2 = new Dog();
console.log(dog2.type); //[ 'pig', 'cat', 'dog' ] //缺陷2:无法为不同的实例初始化继承来的属性,不能向父类的构造函数中传递参数
//无法为不同dog赋值不同的颜色,所有dog只能同一种颜色
console.log(dog1.color); //'white'
console.log(dog2.color); //'white'
__proto__指向了父类的原型对象,这样就拥有了父类的原型对象上的属性与方法。2.构造函数继承
//构造函数继承
//声明父类
function Animal(color) {
this.name = 'animal';
this.type = ['pig', 'cat'];
this.color = color;
}
// 为父类添加共有方法
Animal.prototype.greet = function(sound) {
console.log(sound);
} //声明子类
function Dog(color, age){
Animal.apply(this, arguments); //在子类构造函数内部调用父类构造函数
this.age = age;
} //子类实例继承父类的属性和方法
var dog1 = new Dog('white', 1);
var dog2 = new Dog('red', 2);
dog1.type.push('dog'); console.log(dog1.color); //'white'
console.log(dog1.type); //[ 'pig', 'cat', 'dog' ]
console.log(dog2.color); //'red'
console.log(dog2.type); //[ 'pig', 'cat' ] //缺陷:无法获取到父类的共有方法,也就是通过原型prototype绑定的方法
dog1.greet('wangwangwang'); //TypeError: dog1.greet is not a function
dog2.greet('wangwangwang'); //TypeError: dog2.greet is not a function
构造函数继承方式可以避免类式继承的缺陷,在子类构造函数内部调用父类构造函数。通过使用apply()和call()方法可以改变函数的作用域,在新创建的对象上执行构造函数。
所以在上面的例子中,我们在Dog子类中调用这个方法也就是将Dog子类的变量在父类中执行一遍,这样子类就拥有了父类中的共有属性和方法。
构造函数继承也是有缺陷的,那就是我们无法获取到父类的共有方法,也就是通过原型prototype绑定的方法。
//缺陷:无法获取到父类的共有方法,也就是通过原型prototype绑定的方法
dog1.greet('wangwangwang'); //TypeError: dog1.greet is not a function
dog2.greet('wangwangwang'); //TypeError: dog2.greet is not a function
3.组合继承
组合继承其实就是将类式继承和构造函数继承组合在一起:
//类式继承和构造函数继承结合的组合继承
//声明父类
function Animal(color) {
this.name = 'animal';
this.type = ['pig', 'cat'];
this.color = color;
}
// 为父类添加共有方法
Animal.prototype.greet = function(sound) {
console.log(sound);
} //声明子类
function Dog(color, age){
Animal.apply(this, arguments); //在子类构造函数内部调用父类构造函数
this.age = age;
} //类式继承
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog; //子类实例继承父类的属性和方法
var dog1 = new Dog('white', 1);
var dog2 = new Dog('red', 2);
dog1.type.push('dog'); console.log(dog1.color); //'white'
console.log(dog1.type); //[ 'pig', 'cat', 'dog' ]
console.log(dog2.color); //'red'
console.log(dog2.type); //[ 'pig', 'cat' ] //获取到父类的共有方法
dog1.greet("wang"); //'wang'
dog2.greet("miao"); //'miao' //缺陷 :调用了两次父类构造函数
Dog.prototype = new Animal(); //第一次调用
Animal.apply(this, arguments); //第二次调用
原型链来决定的,由于JavaScript引擎在访问对象的属性时,会先在对象本身中查找,如果没有找到,才会去原型链中查找,如果找到,则返回值,如果整个原型链中都没有找到这个属性,则返回undefined。也就是说,我们访问到的引用类型(比如上面的type)其实是通过apply复制到子类中的,所以不会发生共享。组合继承的缺陷就是它调用了两次父类的构造函数。
//缺陷 :调用了两次父类构造函数
Dog.prototype = new Animal(); //第一次调用
Animal.apply(this, arguments); //第二次调用
4.寄生组合式继承
寄生组合式继承强化的部分就是在组合继承的基础上减少一次多余的调用父类的构造函数。由于现在用的最多的还是组合继承,寄生组合式继承不做深入的探究,有兴趣可以 参考js高程P172 。
总结
JavaScript主要通过原型链实现继承。原型链的构建是通过将一个类型的的实例赋值给另一个构造函数的原型实现的。这样,子类型就能够访问父类型的所有属性和方法,这一点与基于类的继承很相似。
原型链的问题对象实例共享所有继承的方法和属性,修改子类实例对象继承自父类的属性或方法时,会影响新创建的子类实例,因此不适宜单独使用。
解决这个问题的技术是借用构造函数,即在子类型构造函数的内部调用父类型构造函数。这样就可以做到每个实例都具有自己的属性,同时还能保证只使用构造函数模式来定义类型。但是使用这种方式导致的结果就是无法获取到父类的共有方法,也就是通过原型prototype绑定的方法。
使用最多的集成模式是组合继承方式,这种模式综合了类式继承和构造函数继承的优点,同时去除了缺陷。即使用原型链继承共享的属性和方法,而通过借用构造函数继承实例属性。
JavaScript实现继承的方式和各自的优缺点的更多相关文章
- javascript 中继承实现方式归纳
转载自:http://sentsin.com/web/1109.html 不同于基于类的编程语言,如 C++ 和 Java,javascript 中的继承方式是基于原型的.同时由于 javascrip ...
- javascript实现继承的方式
this this表示当前对象,如果在全局作用范围内使用this,则指代当前页面对象window: 如果在函数中使用this,则this指代什么是根据运行时此函数在什么对象上被调用. 我们还可以使用a ...
- JavaScript的继承实现方式
1.使用call或apply方法,将父对象的构造函数绑定在子对象上 function A(){ this.name = 'json'; } function B(){ A.call(this); } ...
- JavaScript 的继承与多态
本文先对es6发布之前javascript各种继承实现方式进行深入的分析比较,然后再介绍es6中对类继承的支持以及优缺点讨论.最后介绍了javascript面向对象编程中很少被涉及的“多态”,并提供了 ...
- javascript实现继承的几种方式
原型链方式实现继承 function SuperType(){ this.property = true; this.colors = ['red','blue','green']; } SuperT ...
- JavaScript各种继承方式和优缺点
好久没写博客啦,嘻嘻,这个月是2017年的最后一个月啦,大家应该都开始忙着写年终总结了吧,嘻嘻,小颖今天给大家分享下Javascript中的几种继承方式以及他们的优缺点. 1.借助构造函数实现继承 原 ...
- DOM笔记(十三):JavaScript的继承方式
在Java.C++.C#等OO语言中,都支持两种继承方式:接口继承和实现继承.接口继承制继承方法签名,实现继承则继承实际的方法和属性.在SCMAScript中,由于函数没有签名,所以无法实现接口继承, ...
- 【编程题与分析题】Javascript 之继承的多种实现方式和优缺点总结
[!NOTE] 能熟练掌握每种继承方式的手写实现,并知道该继承实现方式的优缺点. 原型链继承 function Parent() { this.name = 'zhangsan'; this.chil ...
- javascript继承(七)—用继承的方式实现照片墙功能
照片墙DEMO下载 注意:图片有四种类型:1可放大:2可拖动:3既可放大也可拖动:4都不行.由于每个图片的构造函数不同而不同(目前在火狐上调试的,其它的浏览器可能不行,请见谅,主要讲继承的思想.以后会 ...
随机推荐
- 基于windows消息的响应USB插入或取出
导语:当有设备进入windows时,系统会向所有的应用层发送WM_DEVICECHANGE消息.进一步根据相应的事件判断设备. LRESULT CALLBACK WndProc(HWND hWnd, ...
- react中使用屏保
1,默认路由路径为屏保组件 <HashRouter history={hashHistory}> <Switch> <Route exact path="/&q ...
- JavaWeb中请求转发和请求重定向的区别
针对于JavaWeb中请求与重定向的一个cheatsheep: 1.转发 1)完成一次转发,用户浏览器发送一次请求 2)转发之后,浏览器URL地址栏不改变(服务器帮忙完成) 3)请求域中数据不丢失 4 ...
- Eclipse Java开发环境的搭建
(2019年2月19日注:这篇文章原先发在自己github那边的博客,时间是2016年9月6日) 工作室的老人家们和小朋友们组成了一个Java开发学习团队,想起之前在暑假项目中学过一点Java基础知识 ...
- <数据链接>常用网站收集
1.互联网数据指数 百度指数:http://index.baidu.com/ 阿里指数:http://index.1688.com/ TBI腾讯浏览指数:http://tbi.tencent.com/ ...
- css3之 过渡
早期在Web中要实现动画效果,都是依赖于JavaScript或Flash来完成.但在CSS3中新增加了一个新的模块transition,它可以通过一些简单的CSS事件来触发元素的外观变化,让效果显得更 ...
- js 实现音频播放与暂停
html: <script src="js/jquery-2.1.3.min.js"></script> <div id="soundIco ...
- AlexNet结构图详解
- 如何做系列(4)-微博URL短网址生成算法原理(java版、php版实现实例)
短网址(Short URL),顾名思义就是在形式上比较短的网址.通常用的是asp或者php转向,在Web 2.0的今天,不得不说,这是一个潮流.目前已经有许多类似服务,借助短网址您可以用简短的网址替代 ...
- sql 2000 or sql2005 数据库日志删除
数据库日志清理(sql 2000 or sql2005)DUMP TRANSACTION crm WITH NO_LOGBACKUP LOG crm WITH NO_LOGDBCC SHRINKDAT ...