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

2015-10-21 19:28:53 +08:00
 bramblex

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

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
7451 次点击
所在节点    JavaScript
61 条回复
haibocui
2015-10-21 20:21:40 +08:00
流弊
bramblex
2015-10-21 20:22:43 +08:00
@icymorn 我的目的一向是到哪里都能用 /w\。
hronro
2015-10-21 20:23:36 +08:00
这个确实给力!
iwege
2015-10-21 21:40:09 +08:00
@bramblex

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

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


3 ,不能重载。
可以

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

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

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

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

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

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

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

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

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

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

以前留的坑,忘了改了
icymorn
2015-10-21 23:22:16 +08:00
@iwege
第一次接触这种写法,学到了,非常感谢。
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
2015-10-22 01:02:45 +08:00
少用继承...
HowardMei
2015-10-22 01:12:08 +08:00
好像很黑科技的样子,比 Typescript 的 Overload 强大,可人家是故意不让用 :)
fo2w
2015-10-22 01:52:23 +08:00
对于 lz 这种闲的蛋疼的人我只想说...


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

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

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/229960

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX