聊一聊javascript是应该面向对象式还是函数式

javascript因出身寒酸,诞生之日并没有明确的范型(paradigm),但随着ECMAScript标准的快速发展及babel的编译器超前支持,javascript呈现出多种范型并发发展的趋势。比如es6中规定的class,让javascript成为OO[1]范型成为可能;同样在es6中定义的=>(fat arrow)也让javascript成为FP[2]范型成为可能。在这些可能的范型中,该如何取舍,这是一个曾经困扰我过的问题。

我曾写过10年的C#,我对OO有很深的情结,但是在javascript的世界里,我并没有走向OO,原因大概是:

  1. this就像一个大bug,很多时候错误都是因为它,因为隐蔽所以有时花很多时间调试。再加上=>function的细微差别[3],也让我不敢使用this,如果不用this,那我觉得已经不像OO了;
  2. class中没有private概念,所有的属性从本质上讲都可以被外部访问到,当然可以用比如前缀_来区分,但都很变扭,可以说连OO最基本的封装也没有做到;
  3. 由于缺乏类型和很多特性的支持,javascipt中的OO很难走得太远,比如:IoC容器就很难实现;
  4. 我始终觉得OO中类的颗粒度很难把握,包含的东西稍微多了,就会变成像一个程序一样,充满了全局变量和函数;如果包含的逻辑少了,比如很多的设计模式(如:SingletonCommand、等等),class只有一个方法一个属性,如果是这样何不就一个函数?

而我最终还是渐渐地走向了FP,下面是我能想到的原因:

  1. 尽管javascript不是一个100%的FP语言,但是相对于很多语言,其对于FP的支持要更多些。比如对于FP中最基础的currycompose,我觉得要至少比C#JAVA等很多有FP特性的语言强;
  2. 终于可以摆脱this了,也可以在所有场合用=>了;
  3. 更好的封装性:可以通过curry闭包实现private,反而比OO具有封装性,如下代码所示:
  const add = curry((a, b) => a + b)
  const inc = add(1) // 这个传入的1其实存在在闭包中,外部无法访问,具有极好的可配置封装性
  inc(4) // 5
  1. 更好地代码重用和重构能力:FP优于OO的主要点是:避免了OO随时可变的State[4],因为函数只取决于传入的参数,所以很容易地对代码重构或者重用;

当然,javascript离完美的FP语言还有很多距离,比如:

  1. curry没有语言基本的支持,而javascript的可变参数数量简直是和curry背道而驰。curry要求参数是固定的,如果定义一个curry函数有3个参数,那么调用小于3个参数的情况都会返回一个函数,而给4个参数,它会把函数的返回结果作为函数去调用第4个参数,从而报错,如下所示
const f3 = curry( (a, b, c) => a + b + c)

f3(1)(2) // 返回函数
f3(1, 2) // 返回函数
f3(1, 2, 3) // 6
f3(1, 2, 3, 4) // 报错,说6不是函数。原因是,这个调用相当于f3(1, 2, 3)(4),即6(4)
  1. ImmutableFP的重要特点,FP要求函数都是pure的,没有side effects,所以所有的变量都不能改变值。虽然javascript中有const,但当定义于址类型来说(比如array),并没有达到immutable。要真正达到immutable,有以下办法:
    • 要不只有引入一些库,比如immutable-js,但这这是以破坏程序的可读性为代价的
    • 要不自己手工控制,比如array.push(1)就用array = [...array, 1]来取代,对于简单的操作可以,但对于复杂的操作,这些连接代码会增多,也容易引起错误。
  const array = []
  array.push(1) // 不会报错,但却改变了array的值
  1. 对于compose没有语言层面的支持
  2. 对于FP中的各种基础类型,比如:TaskEitherMonadSemigroup等没有语言层面的支持

尽管如此,javascript的开源社区还是推出了很多库来解决javascript对于FP语言层面支持的缺乏,除了连接代码[5]稍微多了写外,其它都还能接受,经过2年左右的javascriptFP实践,我认为是完全可行的。


  1. OO:Object Oriented,即面向对象

  2. FP:Functional Programming,即函数式编程

  3. =>中的this绑定的是定义时所在的对象,而不是使用时所在的对象,可参考:阮一峰的ECMAScript 6 介绍

  4. OOstateOO最麻烦的是在某一时刻,你不知道其内部的属性值,这对理解代码和调试代码都带来相当的麻烦,就像全局变量。另外,若要实现并发,只能使用多线程技术,而处理多线程之间的协调又是极其困难

  5. 连接代码:指的是没有业务逻辑功能的代码,比如:const f = curry( (a, b) => a + b )curry就是连接代码,作为一个好的架构,连接代码应该越少越好。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容