代码优化之 - pure function - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
buzhiming

代码优化之 - pure function

  •  
  •   buzhiming 2018 年 2 月 4 日 3019 次点击
    这是一个创建于 3000 天前的主题,其中的信息可能已经有所发展或是发生改变。

    很多人在写一个类时会写出这样的代码:

    class Person { talk (name, msg) { this._initName(name) this.msg = msg this._send() } _initName (name) { this.name += ': ' } _send () { console.log(this.name + this.msg) } } 

    我认为更好的写法是这样:

    class Person { talk (name, msg) { this.name = this._initName(name) this._send(this.name, msg) } _initName (name) { return name += ': ' } _send (name, msg) { console.log(name + msg) } } 

    在实现了同样的功能的同时,下面的代码有以下几个优点:

    initName 成为了一个纯函数

    纯函数的特点是没有副作用,如果在该类的其他地方仍需复用这个逻辑,可以直接使用,比如

    const anotherName = this._initName(anotherName) 

    而原来的 initName(name) 因为和 this.name 绑定,无法很好的复用。

    方法意图更加明显,可读性高

    阅读代码 1 时,当看到 talk 的代码时很难看出来 this.initName(name)this.send() 到底在做什么,代码 2 比代码 1 多传递了以下信息:

    • this.initName 改变了 name 的值,并且这个值被赋值到了 this.name 属性
    • this.send 依赖于 name 和 msg

    总结为以下

    • 当一个方法只修改了一个状态(实例属性)时,可以不从该方法内部去修改状态,而是返回这个修改后的值,让调用的方法去处理赋值
    • 当一个方法依赖于其他状态(实例属性)时
      • 如果依赖的状态较少,建议将依赖申明为参数,并从调用处传递依赖
      • 如果依赖的状态特别多且复杂,传参将会变得很麻烦,但是这通常说明这个方法过于庞杂,需要先精简和拆分,再遵从上面的规则优化

    http://buzhiming.me/2018/01/30/func-state/

    viko16
        1
    viko16  
       2018 年 2 月 4 日   2
    那为什么不直接把 _initName 和 _send 抽离出去?别的类复用的时候还少一次实例化呢
    wwqgtxx
        2
    wwqgtxx  
       2018 年 2 月 4 日 via iPhone
    你这种写法在 python 下都会建议你把写法函数改成 classmethod 或者 staticmethod 了
    buzhiming
        3
    buzhiming  
    OP
       2018 年 2 月 4 日
    @viko16 对,_initName 和 _send 是完全可以抽出去的,具体看情况而定吧。
    buzhiming
        4
    buzhiming  
    OP
       2018 年 2 月 4 日
    @wwqgtxx 是的,js 也可以写成 static method,限于篇幅我就没讲那么细啦
    doubleflower
        5
    doubleflower  
       2018 年 2 月 5 日 via Android
    你把数据都从函数里面传进去还要写个类干嘛?不伦不类,面向对象类就是用来封装数据的
    buzhiming
        6
    buzhiming  
    OP
       2018 年 2 月 5 日
    @doubleflower 不对对外暴露的接口做这种优化,所有和类的使用并不冲突。
    doubleflower
        7
    doubleflower  
       2018 年 2 月 5 日
    @buzhiming 这和对外暴露有什么关系。你既然实现用了类,数据就是绑在对象上的,方法是操作对象数据的,你要增加灵活性可以不从对象上取数据,还你的函数为何还要放在类里?定义一个类外的独立函数不是更好?
    buzhiming
        8
    buzhiming  
    OP
       2018 年 2 月 5 日
    @doubleflower 当然有关系,数据封装在了类里面,所以在外面调用类的对外暴露的方法时,只需传必要的参数,而不要去传封装的参数,这些方法是不能优化为纯函数的。

    而供类内部自己使用的私有方法,这么优化是有我说的以上的几点好处的。

    你说的没错,这些函数完全可以放在类的外部作为独立函数,只不过这不是重点。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5281 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 44ms UTC 05:56 PVG 13:56 LAX 22:56 JFK 01:56
    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