javascript的apply()和call()

作为业务的前端开发,有时候看一些代码的时候碰到apply和call方法会觉得很纳闷,好好的一个函数执行,非要写成这样,看了网上的一些事例代码还是没真正理解其不得不用的场景。直到最近自己碰到一个不得不用apply方法的场景,才真正理解了apply和call的作用。

直接看代码:

在这段代码里面,我达到的目的是:通过传递worker对象的make方法的方式来让boss选择生产出那种产品,boss的chooseWorker方法的参数是make方法。我本来期望传给chooseWorker方法的参数如果是foodWorker的make方法就生产food,如果是carWorker的make方法就生产carWorker。期望的结果是这样:

但是结果并不是这样,而是:

那为什么我传递的是指定对象的方法,里面的this.product确实“house”呢?

原因是JavaScript对象的函数本身并不包含对象的信息的信息,如果直接调用makeFunction,其调用方默认是window对象,也就是说this==window,所以this.product就是“house”了。要想达到预想的效果,就得用到apply方法了。比如这样:

其输出结果就打到预期了,对于一些设计模式和继承使用的时候,apply和call会常被使用到。主要是解决this对象的指向问题,当然也可以通过使用apply和call来替换方法的调用者。

apply和call的作用基本相同,唯一的区别是apply有两个参数,而call只有一个参数。

  • apply的第一个参数是函数的调用对象,第二个参数是函数的参数列表(参数数组),上面的代码就是个例子。当然如果函数没有参数,可以给apply方法传空数组([]);
  • call的参数只有一个,就是函数的调用对象。

apply包含了call的功能,所以一般用apply就行了。这是我目前的理解,抛砖引玉。

 

函数式编程——把函数作为参数

函数式编程
函数式编程

网上不少函数式编程的概念都说得好抽象,看不懂,还不如码点代码来得清晰。本文以go语言为例,实践一个函数式编程中小点:把函数作为参数。这也是函数式语言与其他语言的一个很重要的区别,可以显著减少代码量。

实践:把函数作为参数

先看段段代码:

上面的代码,每个err都要判空,还要根据不同情况打印不同级别的日志。代码显得很冗长,难看。怎么办?把判空和输出日志的部分抽成方法,代码应该会清爽很多,改造后如下:

上面的代码,把冗余逻辑抽成单独的方法,主体代码逻辑就简化了,代码清爽了许多。但问题是原来的一个main函数,变成了4个函数,代码行数明显增加了。

好吧,那把三个抽出来的函数合成一个,这样判空的代码就只需要写一份了。看看这样吧:

嗯,这样确实方法数少了,代码行数少了点,但是新增了3个常量。好吧,来看看函数式编程会怎样吧:

上面的代码把函数作为参数,瞬间将代码行数降到最低,逻辑仍然非常清晰。用什么输出日志都由调用方来决定。

这算是一个函数式编程的实践案例吧。尽管用java面向对象的方式也能实现类似的效果,但是想想写出来的代码行数一定不少。话说代码越短,阅读代码的人接受的信息越集中,越容易看懂代码。有时候用函数式的思维来解决问题,你会发现代码好短。

Reference

函数式编程思想