还在纠结 Javascript 的继承?给你们看看什么是黑科技 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
bramblex
V2EX    Javascript

还在纠结 Javascript 的继承?给你们看看什么是黑科技

  •  
  •   bramblex 2015-10-21 19:28:53 +08:00 8141 次点击
    这是一个创建于 3650 天前的主题,其中的信息可能已经有所发展或是发生改变。

    猜猜下面的代码你们猜会是什么效果?

    var A = Class('A', Object) .method('constructor', function(){ this.name = 'a'; }); var B = Class('B', A); B.method('run', function(){ console.log('run'); }); var C = B.extend('C') .method('run', function(a){ console.log('run a: ', a); }) .method('run', function(a,b){ console.log('run a, b: ', a, b); }); var c = C(); c.run(); c.run(1); c.run(1,2); 

    BlxClass

    GitHub

    https://github.com/bramblex/BlxClass

    简介

    一个 Javascript 面对对象的库,让你在 Javascript 用上靠谱的面对对象特性。

    使用

    将本项目中的 dist/Class.js 复制到你的项目下

    1. 在 nodejs 中使用

    var Class = require('path/to/Class.js'); var ClassA = Class('ClassA', Object); 

    2. 在浏览器中使用

    <script src="path/to/Class.js"></script> <script> var ClassA = Class('ClassA', Object); </script> 

    API

    1. Class( class_name, parent_class)

    Class 函数接受两个参数返回一个新类,第一个参数是新类的命名,第二个参数是继承自哪个类。如果并没有继承自别的类,那么直接写 Object 就好了。

    var ClassA = Class('ClassA', Object); var ClassB = Class('ClassB', ClassA); 

    2. name

    类的名字

    var ClassA = Class('ClassA', Object); console.log(ClassA.name) // => ClassA var ClassB = Class('some name', ClassA); console.log(ClassB.name) // => some name 

    3. parent

    类的父类

    var ClassA = Class('ClassA', Object); ClassA.parent === Object; // => true var ClassB = Class('ClassB', ClassA); ClassB.parent === ClassA; // => true 

    4. method( method_name, function )

    定义方法,方法会被子类继承,并且能够重载。

    var ClassA = Class('ClassA', Object) .method('constructor', function(){ // 构造函数 this.name = 'no name'; }) .method('constructor', function(name){ // 重载构造函数 this.name = name; }) .method('run', function(){ // 普通方法 console.log('run'); }) .method('run', function(a,b){ // 重载上面定义的 run 方法 console.log('run a, b: ', a, b); }) .method('run', '*', function(){ // 其他任意参数的情况 console.log(arguments); }); var a = ClassA(); var b = ClassA('Li Lei'); console.log(a.name); // => no name console.log(b.name); // => Li Lei a.run(); // => run a.run(1,2); // => run a, b: 1 2 a.run(4,5,6); // => [4,5,6] a.run(7,8,9,0,1,2,3); // => [7,8,9,0,1,2,3] 

    5. classmethod( method_name, function )

    定义类方法,类方法不会被子类继承,也不能重载。

    var ClassA = Class('ClassA', Object) .classmethod('run', function(){ // 类方法 console.log('class method run'); }); ClassA.run(); // => class method run 

    6. extend( class_name )

    继承出新类。

    var ClassA = Class('ClassA', Object); // 下面两种写法是等价的 var ClassB = Class('ClassB', ClassB); var ClassB = ClassA.extend('ClassB'); 

    7. alias( alias_name , method_name )

    给方法取别名

    var ClassA = Class('ClassA', Object) .method('run', function(){ // 普通方法 console.log('run'); }); ClassA.alias('aliasRun', 'run'); var a = ClassA(); a.run(); // => run a.aliasRun(); // => run a.run === a.aliasRun; // => true 

    8. uper( method_name )

    调用父类方法

    var ClassA = Class('ClassA', Object) .method('run', function(){ // 普通方法 console.log('ClassA run'); }); var ClassB = ClassA.extend('ClassB') .method('run', function(){ ClassB.uper('run').apply(this, arguments); console.log('ClassB run'); }); var ClassC = ClassB.extend('ClassC') .method('run', function(){ ClassC.uper('run').apply(this, arguments); console.log('ClassC run'); }); var c = ClassC(); a.run(); // => ClassA run // => ClassB run // => ClassC run 
    61 条回复    2015-10-22 23:31:36 +08:00
    timeship
        1
    timeship  
       2015-10-21 19:35:06 +08:00
    嘿嘿 在这也能碰见你
    Gonster
        2
    Gonster  
       2015-10-21 19:36:52 +08:00 via iPhone
    啦啦啦, lz 又放黑魔法啦(ω)
    bramblex
        3
    bramblex  
    OP
       2015-10-21 19:43:10 +08:00 via Smartisan T1
    @timeship 不然咧~
    bramblex
        4
    bramblex  
    OP
       2015-10-21 19:45:36 +08:00 via Smartisan T1
    @Gonster 我的黑科技从来都是很逆天的
    lizhenda
        5
    lizhenda  
       2015-10-21 19:49:23 +08:00
    很厉害的样子,确实不错。
    qdwang
        6
    qdwang  
       2015-10-21 19:49:39 +08:00 via Android
    这科技 黑在哪里ǖ
    domty
        7
    domty  
       2015-10-21 19:53:31 +08:00
    只看了第一个 demo
    lz 是用 js 实现了单继承和方法重载?
    iwege
        8
    iwege  
       2015-10-21 19:56:46 +08:00
    `(function(a,b){}).length`?
    bramblex
        9
    bramblex  
    OP
       2015-10-21 19:59:42 +08:00
    @qdwang

    /w\ 其实代码里面用了很多黑科技的
    bramblex
        10
    bramblex  
    OP
       2015-10-21 20:01:13 +08:00
    @lizhenda 必须不错~ /w\
    joyee
        11
    joyee  
       2015-10-21 20:02:53 +08:00
    然而 ES6 已经有 class 和 extend 了……以及更加干净的新语法
    icymorn
        12
    icymorn  
       2015-10-21 20:10:31 +08:00
    @joyee 恩, es6 的 class 很惊艳,不过 @bramblex 还有一些更新的特性,比如根据参数长度重载…… 当然,还是要说,函数式语言好,模板匹配才是王道 ( 逃
    zrp1994
        13
    zrp1994  
       2015-10-21 20:11:01 +08:00 via iPhone
    黑在哪里…
    bramblex
        14
    bramblex  
    OP
       2015-10-21 20:13:43 +08:00
    @joyee

    1 ,没好看也没好用多少。
    2 ,不能把类打开添加新方法。
    3 ,不能重载。
    4 ,没有配套的工具,比如最简单的,假设父类对我是一个黑箱,我需要调用父类的方法怎么办?
    5 ,其实我的这个才更符合人们对基于类继承的面向对象的认知。
    6 ,如果 Javascript 要好好做成基于原型的面向对象语言,那么参考 Io lang ,我也没必要折腾这些了。
    bramblex
        15
    bramblex  
    OP
       2015-10-21 20:17:42 +08:00
    @icymorn JS 在大杂烩这条路上越走越远了
    chendeshen
        16
    chendeshen  
       2015-10-21 20:18:45 +08:00
    黑科技 @!!!
    bramblex
        17
    bramblex  
    OP
       2015-10-21 20:19:15 +08:00
    @zrp1994 js 下的方法重载……还不够黑
    bramblex
        18
    bramblex  
    OP
       2015-10-21 20:20:59 +08:00
    @domty

    是的,单继承和方法重载。

    继承出来的对象能够用 instanceof 检验类型
    bramblex
        19
    bramblex  
    OP
       2015-10-21 20:21:15 +08:00
    @iwege 对的 /w\ 是这样玩的
    icymorn
        20
    icymorn  
       2015-10-21 20:21:25 +08:00
    @bramblex es6 可重载,而且对于我来说,看起来和其它语言里面的类声明更相近也更容易理解。
    父类是个黑箱…… 这本来就是面向对象的思路吧,不关心黑箱,当然,要是有个逗逼写了个类太难用,只好 hack 回去就没法说了。
    es6 目前支持度着急,浏览器上自己实现类的确按照你这样有很多便利。
    haibocui
        21
    haibocui  
       2015-10-21 20:21:40 +08:00
    流弊
    bramblex
        22
    bramblex  
    OP
       2015-10-21 20:22:43 +08:00
    @icymorn 我的目的一向是到哪里都能用 /w\。
    hronro
        23
    hronro  
       2015-10-21 20:23:36 +08:00
    这个确实给力!
    iwege
        24
    iwege  
       2015-10-21 21:40:09 +08:00   1
    @bramblex

    1 ,没好看也没好用多少。
    从 stage 0 开始看起. import 反正我已经吐槽过了。但是 class 绝对是一个好帮手。

    2 ,不能把类打开添加新方法。
    prototype 还是可以访问的。也可以用子类的方式扩展。还有 es7 的 decorators 草稿标准。


    3 ,不能重载。
    可以

    4 ,没有配套的工具,比如最简单的,假设父类对我是一个黑箱,我需要调用父类的方法怎么办?
    if(super.fn){super.fn()}

    5 ,其实我的这个才更符合人们对基于类继承的面向对象的认知。
    有争议

    6 ,如果 Javascript 要好好做成基于原型的面向对象语言,那么参考 Io lang ,我也没必要折腾这些了。
    我觉得是一个方向性错误。
    iwege
        25
    iwege  
       2015-10-21 21:43:03 +08:00
    https://gist.github.com/iwege/d77cca95bb1dc8a41f9

    上面是用 stage 0 的标准模仿楼主写的简单的方法。逻辑上可能有副作用,只是证明可行性。

    上面实际执行的结果如下:
    1
    print all {}
    print all { '0': 1, '1': 2, '2': 3 }
    [Function: fn2]
    fn2, print from base
    fn2 from Class A
    joyee
        26
    joyee  
       2015-10-21 22:31:30 +08:00
    @bramblex 2 3 4 均不成立……原因同 @iwege

    1 总归是比现有的不修改语法的其他方法好看些 5 6 他们( TC 39 )志不在此 支持度有 transpiler 帮手……
    banri
        27
    banri  
       2015-10-21 22:46:52 +08:00
    @joyee 拜大神
    iamcho
        28
    iamcho  
       2015-10-21 22:48:06 +08:00
    mark
    bramblex
        29
    bramblex  
    OP
       2015-10-21 22:54:19 +08:00
    @joyee

    那还不如造新语言来的靠谱……真的……
    bramblex
        30
    bramblex  
    OP
       2015-10-21 22:55:30 +08:00
    @iwege

    支持度欠佳, chrome 上面还硬性要求 strict mode
    bramblex
        31
    bramblex  
    OP
       2015-10-21 22:58:51 +08:00
    @joyee

    志不在此那最好,把基于类继承的面向对象忘的干干净净,老老实实看看别人 Io lang 基于原型链继承多正常。

    现在这个大杂烩搞得乱七八糟的,还一堆不兼容问题。好歹我这个扔那里都能用
    liangqing
        32
    liangqing  
       2015-10-21 23:09:52 +08:00
    提醒楼主,函数的 name 属性是个只读属性,所以设置也没用,有的浏览器还会抛异常。
    bramblex
        33
    bramblex  
    OP
       2015-10-21 23:19:44 +08:00
    @liangqing

    以前留的坑,忘了改了
    icymorn
        34
    icymorn  
       2015-10-21 23:22:16 +08:00
    @iwege
    第一次接触这种写法,学到了,非常感谢。
    iwege
        35
    iwege  
       2015-10-22 00:14:01 +08:00
    @bramblex
    这只是一个简单的 demo ,特性上我觉得没有什么,只是觉得语法上你的这种写法很嗦而已,部分实现的话新特性也可以支持,比如上面 fn 重复定义的问题,使用我的那个方法也可以简单的解决掉。上面的案例已经修改了。
    https://gist.github.com/iwege/d77cca95bb1d8c8a41f9

    同时尝试了自定义 class ,估计有点麻烦,但是也不是不可行。 overloadClass 可以支持拿到 class function 本身。

    至于所谓的支持度,在有 transpiler 的情况下我向来不关心,我关心的是前端工程化,编码高效化以及问题定位速度。就像习惯了 coffee 或者 om 之后你让我再回去写 es5 的 js ,我是断然不乐意的。我的研究也只要能在 V8 里面跑就 OK 。



    @icymorn

    我也是第一次尝试用这个特性来做,因为工程化的话这种灵活性可能会是一种麻烦。当然既然用了 stage 0 干脆连`::`的写法也一起尝试用了。不过楼主的特性还不能完全支持,不知道混用两种方法能不能达到完全处理。
    miro
        36
    miro  
       2015-10-22 01:02:45 +08:00
    少用继承...
    HowardMei
        37
    HowardMei  
       2015-10-22 01:12:08 +08:00
    好像很黑科技的样子,比 Typescript 的 Overload 强大,可人家是故意不让用 :)
    fo2w
        38
    fo2w  
       2015-10-22 01:52:23 +08:00
    对于 lz 这种闲的蛋疼的人我只想说...


    已粉...
    joyee
        39
    joyee  
       2015-10-22 02:04:49 +08:00 via Android   1
    @bramblex 世界上只有两种语言,没人用的和被人骂的。。。论语言设计, 随便路边拦一个谁都能完爆 js ,又何苦拿它开刀。正是因为用的人太多,才不好丢掉历史包袱啊。

    另外你用 transpiler 能有多少兼容性问题,转译出来的代码也就跟人手写这种类的差不多。。。
    adspe
        40
    adspe  
       2015-10-22 09:37:03 +08:00
    Javascript 适用的场景用一般的几种模式的继承已经够了。如果放在一些 scale 比较大的场景会有很多意想不到的后果。
    bramblex
        41
    bramblex  
    OP
       2015-10-22 10:07:13 +08:00
    @joyee

    也是哈 /w\, 就是我比较喜欢造轮子
    bramblex
        42
    bramblex  
    OP
       2015-10-22 10:08:00 +08:00
    @adspe

    比如捏?什么意想不到的后果?
    bramblex
        43
    bramblex  
    OP
       2015-10-22 10:08:38 +08:00
    @iwege

    /w\ 好吧……
    bramblex
        44
    bramblex  
    OP
       2015-10-22 10:09:32 +08:00
    @miro

    面向对象语言我不用继承用什么?

    难道有 typeclass 给我用嘛……
    coolicer
        45
    coolicer  
       2015-10-22 10:18:44 +08:00
    好东西,但是很少用继承。
    magicdawn
        46
    magicdawn  
       2015-10-22 11:36:05 +08:00
    看了 xxxScript 源码, 炒鸡反感~没想到 LZ 还拿出说~
    wdhwg001
        47
    wdhwg001  
       2015-10-22 12:07:22 +08:00
    还是觉得 Blackscript 法比较好,就是阮一峰提到的所谓 Minimalist Approach …
    http://www.gabordemooij.com/blackscript

    不得不说.method 有点太丑了。
    脑补一个语法的话…
    https://gist.github.com/wdhwg001/9f83c9c21754d538886e

    大致想了一下可以用 get:function()和 set:function()一类的诸多黑魔法实现…
    bramblex
        48
    bramblex  
    OP
       2015-10-22 13:01:43 +08:00
    @wdhwg001

    丑是丑,但是用起来还算顺手。如果要更简洁的语法的话,只能改语言语法本身了。
    bramblex
        49
    bramblex  
    OP
       2015-10-22 13:05:09 +08:00
    @magicdawn

    嗯,等你造一个更好用的我就用你的。 OwO
    zythum
        50
    zythum  
       2015-10-22 13:05:54 +08:00
    一般吧。这个多态判断不麻烦。
    比较难的设计是访问权限 publish private, 和 优雅的 super 的设计 用 apply 的方式却是可用而且实用,但是太丑了了
    bramblex
        51
    bramblex  
    OP
       2015-10-22 13:08:40 +08:00
    @zythum

    其实重点不是难不难,判断麻不麻烦,而是好像没什么人想到……
    zythum
        52
    zythum  
       2015-10-22 13:09:52 +08:00
    @bramblex 什么没有人想到啊。老早就有了。只是你没有发现而已...
    ggiiss
        53
    ggiiss  
       2015-10-22 13:30:36 +08:00
    请参考 John Resig 大神 08 年的作品 http://ejohn.org/blog/simple-Javascript-inheritance/
    catface
        54
    catface  
       2015-10-22 17:28:05 +08:00
    项目描述是“ Javascript 的面对对象库”
    ianva
        55
    ianva  
       2015-10-22 17:53:23 +08:00
    以前到热衷鼓捣这些东西, class 实现过这些,还有 mixin , attribute , aop 的功能,不过现在看来,除非整套体系都是自己造的,现在意义没这么大,这个时代已经不是基础工具造轮子的时代了,语言层面的标准化在是重要的,比如之前的 yui 3 的 base , widget 都很强大,但现在已经不维护了。
    aivier
        56
    aivier  
       2015-10-22 17:59:37 +08:00
    这么久了,我还是不知道“面相对象”是个什么。。。
    Justineo
        57
    Justineo  
       2015-10-22 18:24:37 +08:00
    黑科技黑在哪里……实现了啥独有的功能?根据参数长度重载?随便 Google 一下 Javascript overloading ,上来就有 John Resig 的这篇:

    http://ejohn.org/blog/Javascript-method-overloading/ 你自己看看时间吧……

    再搜下会发现也有根据参数类型重载的。

    还有你给的这些示例代码,命名一会儿全小写,一会儿下划线分隔,一会儿驼峰。还有调用父类方法的那个 `uper` 我猜是 `upper` 拼错了吧,但其实应该是 `super`。
    bramblex
        58
    bramblex  
    OP
       2015-10-22 18:40:00 +08:00
    @Justineo

    首先命名规范你喷个毛线?类 开头大写驼峰, 方法开头小写驼峰, 变量小写下划线这个有槽点我没看出来那里有槽点?

    其次,我自己什么都没看就实现了跟 John Resig 一样的东西,那你的意思是不是我跟 John Resig 大神一个水平啊?那你有资格喷个毛?

    我造一个玩具碍着你事了?无语
    bramblex
        59
    bramblex  
    OP
       2015-10-22 18:53:55 +08:00
    @ggiiss

    看这个大神的作品对我没有任何提高……
    kokutou
        60
    kokutou  
       2015-10-22 19:12:29 +08:00
    @aivier 在 IDE 里面,万物皆可打点,然后出一大堆东西。。。
    Justineo
        61
    Justineo  
       2015-10-22 23:31:36 +08:00
    @bramblex 这点喷就受不了了,真的是好可爱。你怎么不反驳一下 uper 是什么啊。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2518 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 10:05 PVG 18:05 LAX 03:05 JFK 06:05
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86