简体   繁体   中英

Javascript code block as a parameter for a function

Given this piece of code (simplification of a React component I came by):

const myFn = function(
  {otherFn = () => {console.log('inside myFn declaration'); return 'true'}}
  ){
      console.log('Inside myFn2 ', otherFn());
      foo(otherFn);
      bar(otherFn);
      ...
}

myFn({name:'some name', type: 'some type'});
// output:
// inside myFn declaration
// Inside myFn2  true

I don't understand what is going on there. What's this construct? I'm referring to what is inside 'myFn()'

This construct/code-block is being called no matter what argument (therefore it doesn't behave as a default parameter)

What's more, the purpose of it seems to be 'otherFn' being made available inside the implementation of the function so it can be passed as a callback to other functions.

If the goal was to have otherFn available inside myFn body, it could have been implemented (in a maybe easier way to understand) as:

const myFn = function(){
  otherFn = () => {console.log('inside myFn declaration'); return 'true'}
  console.log('Inside myFn2 ', otherFn());
  foo(otherFn);
  bar(otherFn);
    ...
  }
}
// Output exactly the same as above

There has to be a simple explanation of what this construct is, but I don't seem to be able to connect it with anything I know of JavaScript.

Any hints on what's going on?

EDIT to include some of the answers: Interestingly, if I use this code like:

function myFn({
  name: 'some name',
  type: 'some type',
  otherFn: () => { console.log("other function"); return false; }
}){
  console.log('here');
} 

it does not work :-( using either node or console of chomium In order for it to work, the ':' should be '=' because it is assigning default values.

More EDIT. I've chosen Thomas' answer because although others have hinted me in the right direction (thanks Benjamin, Ainitak and all) I failed to fully 'see' it until I read Thomas' detailed explanation.

Thank you guys you're the best!

This combines two features:

default value for an argument:

 const fn = (value = 42) => { console.log("value:", value); } fn(13); fn(); 
 .as-console-wrapper{top:0;max-height:100%!important} 

wich is basically a shorthand for

const fn = (value) => { 
  if(value === undefined) value = 42;

  console.log("value:", value);
}

And object destructuring as an agument

 const fn = ({ foo, bar }) => { console.log(foo, bar); } fn({ foo: 10, bar: 100 }); fn({ foo: 13 }); fn(window.location); 
 .as-console-wrapper{top:0;max-height:100%!important} 

basically

const fn = (__arg) => { 
  let foo = __arg.foo;
  let bar = __arg.bar;

  console.log(foo, bar);
}

Just that __arg is just a value that doesn't have an actual name inside your function.


Summary:

const myFn = function({
  otherFn = () => {
      console.log('inside myFn declaration'); 
      return 'true'
    }
  }){
      console.log('Inside myFn2 ', otherFn());
      foo(otherFn);
      bar(otherFn);
      ...
}

is just the combination of these two features: Object destructuring of an argument with a default value for that argument that just happens to be a function.

Works like this:

const myFn = function(__arg){
  let otherFn = __arg.otherFn;
  if(otherFn === undefined){
    otherFn = () => {
      console.log('inside myFn declaration'); 
      return 'true' //why 'true' as a string?
    }
  }

  console.log('Inside myFn2 ', otherFn());
  foo(otherFn);
  bar(otherFn);
  ...
}

What's more, the purpose of it seems to be 'otherFn' being made available inside the implementation of the function so it can be passed as a callback to other functions.

If the goal was to have otherFn available inside myFn body, it could have been implemented (in a maybe easier way to understand)

The purpose of this construct is to provide you (who uses/calls the function) with the ability to inject this method into the function as some property of the configuration object and provide a fallback/default, if you don't pass this config property.

Imo the only uncommon thing about this construct is that the type of this property is function and that they have chosen to inline the function that serves as the default value.

It's object destructuring syntax for the function parameter, with an arrow function as the default initialiser for the otherFn property.

You can use it like

myFn({
    name: 'some name',
    type: 'some type',
    otherFn: () => { console.log("other function"); return false; }
});

I finally understood 'what is the construct there'. It is 2 things simultaneously:

  • object deconstruction
  • default parameter values for the one deconstructed part

Of course I know what each of these are, but the fact that the only part of the object being deconstructed was a function, which in turn was being provided with a default inline implementation got me all but confused all the time.

Also, I was at a loss of understanding why the implementation was done this way instead of some more readable way (eg inside the body of the function). As Thomas suggests, now I understand that that is a way for the caller of the function to provide an implementation for the inner function (which has a default implementation 'just in case').

It has had me thinking a while, but it is nice when you get to finally understand it. Thank you all!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM