JavaScript style for optional callbacks

2019-01-10 06:01发布

I have some functions which occasionally (not always) will receive a callback and run it. Is checking if the callback is defined/function a good style or is there a better way?

Example:

function save (callback){
   .....do stuff......
   if(typeof callback !== 'undefined'){
     callback();
   };
};

10条回答
地球回转人心会变
2楼-- · 2019-01-10 06:16

ECMAScript 6

// @param callback Default value is a noop fn.
function save(callback = ()=>{}) {
   // do stuff...
   callback();
}
查看更多
成全新的幸福
3楼-- · 2019-01-10 06:21

Rather than make the callback optional, just assign a default and call it no matter what

const identity = x =>
  x

const save (..., callback = identity) {
  // ...
  return callback (...)
}

When used

save (...)              // callback has no effect
save (..., console.log) // console.log is used as callback

Such a style is called continuation-passing style. Here's a real example, combinations, that generates all possible combinations of an Array input

const identity = x =>
  x

const None =
  Symbol ()

const combinations = ([ x = None, ...rest ], callback = identity) =>
  x === None
    ? callback ([[]])
    : combinations
        ( rest
        , combs =>
            callback (combs .concat (combs .map (c => [ x, ...c ])))
        )

console.log (combinations (['A', 'B', 'C']))
// [ []
// , [ 'C' ]
// , [ 'B' ]
// , [ 'B', 'C' ]
// , [ 'A' ]
// , [ 'A', 'C' ]
// , [ 'A', 'B' ]
// , [ 'A', 'B', 'C' ]
// ]

Because combinations is defined in continuation-passing style, the above call is effectively the same

combinations (['A', 'B', 'C'], console.log)
// [ []
// , [ 'C' ]
// , [ 'B' ]
// , [ 'B', 'C' ]
// , [ 'A' ]
// , [ 'A', 'C' ]
// , [ 'A', 'B' ]
// , [ 'A', 'B', 'C' ]
// ]

We can also pass a custom continuation that does something else with the result

console.log (combinations (['A', 'B', 'C'], combs => combs.length))
// 8
// (8 total combinations)

Continuation-passing style can be used with surprisingly elegant results

const first = (x, y) =>
  x

const fibonacci = (n, callback = first) =>
  n === 0
    ? callback (0, 1)
    : fibonacci
        ( n - 1
        , (a, b) => callback (b, a + b)
        )
        
console.log (fibonacci (10)) // 55
// 55 is the 10th fibonacci number
// (0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...)

查看更多
相关推荐>>
4楼-- · 2019-01-10 06:21

If the criteria for running the callback is that whether its defined or not, then you're fine. Also, I suggest to check if its really a function in addition.

查看更多
地球回转人心会变
5楼-- · 2019-01-10 06:22

Simply do

if (callback) callback();

I prefer to call the callback if supplied, no matter what type it is. Don't let it fail silently, so the implementor knows he passed in an incorrect argument and can fix it.

查看更多
手持菜刀,她持情操
6楼-- · 2019-01-10 06:31

I personally prefer

typeof callback === 'function' && callback();

The typeof command is dodgy however and should only be used for "undefined" and "function"

The problems with the typeof !== undefined is that the user might pass in a value that is defined and not a function

查看更多
聊天终结者
7楼-- · 2019-01-10 06:31

A valid function is based on the Function prototype, use:

if (callback instanceof Function)

to be sure the callback is a function

查看更多
登录 后发表回答