JavaScript继承主要是两种形式:
1. 原型链继承
2. 拷贝继承
注:ES7标准中的class就暂时不考虑了,因为还没有具体去了解过,希望以后能完善到不需要自己实现那么那么蛋疼的东西了。
我个人倾向于原型链继承,因为原型链继承是JavaScript规范里面推荐的继承,并且最重要的是,可以用原生的 instanceof 判断类型!而拷贝继承不行!
因为以上的一些问题,所以我就自己做了一个简单的JavaScript面的对象库。大概有实现这么几个功能:
1. 封装好的构造函数不管写不写new操作符都不会产生错误了,当然我是倾向于不写new操作符。
2. 返回的构造函数是命名的,方便调试的时候追踪函数栈。
3. 封装了一个parent方法,可以方便访问父原型的构造函数或者父原型的方法。
4. 封装了一个alias方法,可以创建一个方法别名。
具体实现在具体实现在github上 >> 代码传送门
接下来来看一些简单的示例来看看怎么用。
// 首先定义一个Animal类(姑且称为类吧),继承自Objec,有一个构造函数。
var Animal = BlxClass.extend('Animal', Object, function(name, sound){
this.name = name || null;
this.sound = sound || null;
});
Animal.prototype.call = function(){
console.log(this.sound);
};
// 现在我希望定义一个doge类,继承自Animal。第一个参数 ‘Doge’ 是用来给构造函数命名的。
var Doge = BlxClass.extend('Doge', Animal, function(name){
var sound = 'wang';
BlxClass.parent(this, Doge, [name, sound]); // 调用父类的构造函数,因为初始化对象属性在父类构造函数里。
});
Doge.prototype.wang = BlxClass.alias('call');
// 现在实例化一个doge对象
var doge = Doge('Tom'); // 有没有 new 都没关系,结果相同。
doge.call(); // =>'wang'
doge.wang(); // =>'wang'
然后这样就跟其他语言类的继承大致相似了。然后大家更喜欢哪一种继承方式呢?都来说说自己看法吧。
2
exoticknight 2015-06-12 21:56:19 +08:00
大神 Douglas Crockford 的代码
if ( typeof Object.create !== 'function' ) { Object.create = function ( o ) { function F() {} F.prototype = o; return new F(); }; } http://javascript.crockford.com/prototypal.html |
3
bramblex OP |
4
hbkdsm 2015-06-12 22:03:51 +08:00 1
论茴香豆的茴有几种写法
|
5
icymorn 2015-06-12 22:08:11 +08:00
我没用到这种专门搞一个继承的方法,js太灵活了,很多问题在c++首先想到继承解决,而在js中奇技淫巧耍耍就解决了。当然,要我写一个继承,首先从原型链上搞起。
|
6
bramblex OP |
8
hbkdsm 2015-06-12 22:18:18 +08:00
@bramblex 最简洁的应该是 ES6 的 class-extends-super 这一套语法糖,Nodejs 的 util.inherits 也很好啊。你掌握之后应该就很厉害了,因为你终于知道茴有几种写法了!
|
9
yangff 2015-06-12 22:22:37 +08:00
class 的继承方式我记得就是原型继承的语法糖? <求确认
|
12
yangmls 2015-06-12 22:35:45 +08:00 1
|
13
bramblex OP @yangmls
1. eval 是两个作用: 1.1. 命名。如果没有命名在chrome下输出的东西太难看了,受不了。虽然不命名也可以。 1.2. 没有办法 new func.apply(this, args),所以只能事先把从constructor里面读出来有几个参数,然后用arguments[0], arguments[1] ....这样写进去。 2. childe 的 prototype 直接 new 了 parent。然而是会出点问题,现在马上解决掉。 3. Backbone那么个方案我没看过……但是不能光会用别人的东西嘛,对吧。 |
14
pinxue 2015-06-12 22:52:16 +08:00
在 JavaScript 里仿 Class 的都是异端!
ES5之前: var o = { foo:bar, proto: p }; ES5加了: var o5 = Object.create(p); |
15
bramblex OP |
16
YuJianrong 2015-06-12 23:11:13 +08:00 via iPhone 2
我在公司做的class系统是原型链继承,还算好用吧。
对于构造函数没加new这个我以前是赞成不写也new出来的做法,不过现在不赞成了,如果新做一个我一定要抛异常。原因很简单:我不希望做一件事情有多种不一样的做法,如果大家做法一样的话,重构或者静态代码分析都会简单很多,这对于大规模协同开发很重要(jQ是反例)。 我在这个之上还做了destroy方法,这个方法会自动迭代调用父类的destroy方法,并会清空对象成员,保证已销毁对象在大多数情况下使用会崩溃,以第一时间找到问题点。 |
17
bramblex OP |
18
lrvy 2015-06-12 23:24:14 +08:00
JJ的思念
|
20
yangmls 2015-06-12 23:40:45 +08:00
借鉴一下把
var extend = function(protoProps, staticProps) { var parent = this; var child; // The constructor function for the new subclass is either defined by you // (the "constructor" property in your `extend` definition), or defaulted // by us to simply call the parent constructor. if (protoProps && _.has(protoProps, 'constructor')) { child = protoProps.constructor; } else { child = function(){ return parent.apply(this, arguments); }; } // Add static properties to the constructor function, if supplied. _.extend(child, parent, staticProps); // Set the prototype chain to inherit from `parent`, without calling // `parent` constructor function. var Surrogate = function(){ this.constructor = child; }; Surrogate.prototype = parent.prototype; child.prototype = new Surrogate; // Add prototype properties (instance properties) to the subclass, // if supplied. if (protoProps) _.extend(child.prototype, protoProps); // Set a convenience property in case the parent's prototype is needed // later. child.__super__ = parent.prototype; return child; }; // 如何用 var BaseObject = function() {}; BaseObject.extend = extend; var Dog = BaseObject.extend({ call: function() {}... }); //当然,new是必须的 var dog = new Dog |
21
yangmls 2015-06-12 23:41:23 +08:00
|
22
neoblackcap 2015-06-12 23:56:17 +08:00
是我的理解有问题吗?原型继承不就是指所有的新对象都是靠拷贝原型来的嘛?楼主你提这两个东西在底层真的有很大的区别吗?你确定不是跟class一样是个语法糖?
|
23
bramblex OP |
24
neoblackcap 2015-06-13 01:19:43 +08:00
@bramblex 若是可以的话,我想知道是如何划分这两种继承方式,因为我在网上也找不到“拷贝继承”这基本概念,翻GoF里面也没见过。看mdn都是说的是原型链继承
|
25
hbkdsm 2015-06-13 02:01:19 +08:00
@neoblackcap 我理解的 @bramblex 所谓的拷贝继承应该就是 mixin,不知道对不对。可问题是 ... mixin 根本就不是继承啊!
|
26
bramblex OP @hbkdsm
https://zh.wikipedia.org/wiki/%E7%BB%A7%E6%89%BF_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6) 首先,拷贝继承是mixin没错了。但是你好像对继承的概念理解有些问题…… |
27
bramblex OP @neoblackcap
@hbkdsm 不对,拷贝继承不是mixin……或者只能说有些时候mixin是拷贝继承的一个步骤而已…… http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.html |
28
Zhang 2015-06-13 10:42:59 +08:00
没必要写javascript了,可以写其他语言再transcompile成javascript就行了。
|
29
bramblex OP @Zhang 嗯,等我先把JavaScript折腾到极致了我再去转coffee,type之类的好了。不过我觉得应该折腾不到机制 OwO。因为折腾完了JavaScript语言本身,还有v8可以折腾
|
30
Zhang 2015-06-13 11:15:39 +08:00
@bramblex java、c/c++、php、objective-c、c#都可以翻译成javascript,没有必要折腾coffee,type之类的了。
|
31
Zhang 2015-06-13 11:21:38 +08:00
@bramblex 前几天发现几乎所有语言都可以transcompile成javascript,看来不知有多少人对javascript不满啊!
|
33
neone 2015-06-13 12:16:32 +08:00
各有各的用处吧。
《Javascript高级程序设计 第三版》中 6.3.4 ‘原型式继承’ 一节中提到 “他(Douglas Crockford)的想法是借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型”, “ECMAScript5通过新增Object.create()方法规范了原型式继承”。 所以我理解为如果想继承一个对象的同时又不想创建自定义类型的时候可以使用‘原型式继承’,其他的时候应该考虑‘寄生组合式继承’。 |
34
bramblex OP @Zhang JavaScript有问题,但是不能否认JavaScript各种很好的特性。比如函数式的特性,比如闭包等等。
至于有那么多语言翻译成JavaScript,只能说明JavaScript火了。然后那些并不了解JavaScript又不想学习的人开始需要用自己熟悉的语言来实现JavaScript的项目了。 但是当然啦,JavaScript这货虽然有很多优秀的特性,但是坑也是一堆一堆的。说的难听点,JavaScript现在还根本就是断手断脚的残缺品嘛…… TnT |
35
neoblackcap 2015-06-13 13:58:03 +08:00
@bramblex 我觉得你说的拷贝继承根本不能算是继承。所以才提出JS里面有继承也就是原型继承的论调。这个所谓的拷贝继承根本就是原型继承的那套思想,但是实现却用浅拷贝,我觉得只能算是一种实现方式,按道理实现原型拷贝要用深拷贝才对,浅拷贝的话,你修改子类对象一样会修改到父类对象,这样的效果就明显跟继承的初衷不符,跟OO思想不符。
|
36
jings 2015-06-13 14:29:13 +08:00
|
37
bramblex OP |
38
magicdawn 2015-06-13 15:16:25 +08:00
|
39
sodatea 2015-06-13 15:25:04 +08:00
首先,class 是 ES6 标准不是 ES7
|
41
arbipher 2015-06-13 15:49:27 +08:00
我建议使用ES6的class关键字和babel
|
42
bramblex OP |
43
exoticknight 2015-06-14 18:55:53 +08:00
我觉得讨论这么多,都老是想用类的继承来写 javascript,然而 js 中的原型机制根本就不是类的机制,而是能够模拟实现类的机制。
所以要怎么用就怎么写,需要查找原型链那么就直接将 new function 的 prototype 直接等于被继承对象的 prototype。希望被继承对象不会被修改就深复制其 prototype 作为新对象的 prototype。 比如我在自己的项目中需要的只是原型链的查询实现变量作用域的嵌套 https://github.com/exoticknight/simpleTemplate.js/blob/master/simpleTemplate.advanced.js 所以用大神 Douglas Crockfor 的代码就够了。 |
44
bramblex OP @exoticknight
但是为什么不能总是想着类继承来些JavaScript呢?类继承机制在绝大多数情况下确实比原型机制更直观也更好用。其实为什么一定要拘泥于语言本身所谓“够了”的特性,而不能追求更直观更方便更强大的特性呢? 我觉得永远都没有什么 xxxx 就够了这么一说。 |
45
exoticknight 2015-06-14 21:37:49 +08:00
@bramblex
看清楚我的表达,什么什么就够了是有条件的,不要歪曲了。不用原型链而非要用其模拟类继承并非不可以,然而若写简洁的代码就能完成任务为什么还要增其实体? 另外,我不认为“类继承机制在绝大多数情况下确实比原型机制更直观也更好用”,那是可能因为你先学了 OOP 而已。 而你所谓的“更直观更方便更强大的特性”也只是主观因素。 我也没有认为 js 超越其他语言,因为<del>PHP才是最好的语言</del>。我只是想说 js 的原型链能解决,就不要用类继承了。 当然如果你只写ES6,我无话可说。 |
46
bramblex OP @exoticknight
如果js原型链能解决?嗯,那请问,在计算机上有什么能够用0和1解决呢?既然能解决,那干嘛还需要语言? 问题不是能不能解决,而是能不能更好的解决,尽量避免重复,尽量避免接触丑陋的底层细节,而不是“能解决”。 抱歉,我觉得我们还是就此打断这种毫无意义的价值观争端吧。欢迎讨论技术问题 |
47
exoticknight 2015-06-15 19:52:16 +08:00
@bramblex
貌似价值观问题是你先提出的 “问题不是能不能解决,而是能不能更好的解决”。我就一句话,js 上用原型链比类继承更“尽量避免重复,尽量避免接触丑陋的底层细节,而不是“能解决”。 ” 在想如何用类的时候你已经自我矛盾了。 |
48
bramblex OP |
49
bramblex OP @exoticknight
所以还是就此打住吧,别让这种没有营养的口水战继续下去了好吗?自始至终你根本拿不出任何证据来支撑你的论点——原形链继承比类继承好。同样的,我根本也找不出任何证据来反驳你。所以我们能不讨论这种圣战性质的谁比谁好的问题吗? 所以我们能单纯的讨论原形链继承和类继承分别有啥好有啥不好不行吗?如果不好,那我只能说一句了,PHP是最好的编程语言。 |
50
exoticknight 2015-06-15 20:31:02 +08:00
@bramblex
行,本来打算继续补充,怕你已经 block 了我所以没发。 1、原型链本身就是原生的方式,js 本身并不支持类继承,写类的 polyfill 本身就是强行加细节。 2、原型链机制在最少代码情况下用之前我贴出的代码就 ok,相反你看类继承包括你在内建了多少楼?又用了多少代码? 我也只是呼吁一下 js 有其独特的方式,写的时候多运用,而不要老想着上其他语言的那一套而已。 我在写 node 的时候觉得 inherit 也是很好的,但反对所有地方都用。 |
51
exoticknight 2015-06-15 20:33:19 +08:00
@bramblex
喂喂,分明你自己也没有提出证据全是问句啊……还直接说我了唉…… |
52
bramblex OP @exoticknight
1. 首先我已经直说了我提不出证据反驳你啊……这个我记得我是清清楚楚写在上面了吧,不然您再仔细看看? 2. 即便你说的全都对,但是依旧没有证明你所说的“原型链继承比类继承更优”啊。能得出的结论只是我的实现比你多了几十行代码而已。 3. “我也只是呼吁一下 js 有其独特的方式,写的时候多运用,而不要老想着上其他语言的那一套而已。 ”这句话真的一点意义都没有,不行我反着给你说一遍: 我也只是呼吁一下大家要多想想其他的解决方案,写的时候多思考,而不要老是被js那一套限制住了思维而已。 4. 我不反对任何人在任何情况下写任何代码,除非我是他boss。不然我觉得我真的没有任何权力去反对别人写怎么样的代码唉,我能想象我反对别人写怎么样的代码的时候,别人会白我一眼然后淡淡回我一句:管你屁事。 |
53
exoticknight 2015-06-15 21:20:37 +08:00
@bramblex
1、我说的是更前的地方。43楼我表达了“哪里用什么就ok了没必要硬要用某模式”,44楼你自己说“类继承机制在绝大多数情况下确实比原型机制更直观也更好用。”,并没有提出证据,我说的是这里。之后我提出并非如此你反而要我提证据了。 2、如果全都对,*在使用 js 情况下*,为什么就没有证明更优?你这种情况不就是尝试在 java 中用原型链的行为不是? 3、这句话我承认自己脑子的确被驴踢了。 4、我从来没有指明反对你写什么代码,也承认类继承有其可用之处,你要写 babel 也好写 compiler 也好,管我屁事。难道我在论坛上提出观点也不行了? 还是打住吧 虽然说“如果是两个理性而真诚的真理追求者争论问题,争论的结果必然是二人达成一致。”,但是我还有其他事情要做…… |
54
bramblex OP |