Functions

Definition

There are two ways to define a function, either by assigning it to

Creating a named function:

function testicle() {
    console.log('poo far');
}

console.log(testicle.name); // testicle

if you omit the name, you create an 'anonymous' function. Unless you immediately invoke it or assign it to a variable you will not be able to refer to it again.

Assigning to variable:

const testicle = function () {
    console.log('poo far');
}

console.log(testicle.name)// '' (empty string)

Assigning to a variable does not give a name to the function.

const testicle = function () {
    console.log('poo far');
};

// TODO fix wording This means a function can have different name from variable. However, you cannot call it by it's name. TODO Why can you not call it by its name now?

const testicle = function penis() {
    console.log('poo bar');
};

console.log(testicle.name)// 'penis';

testicle();// 'poo bar'

penis();// ReferenceError

The following does work, Though I do not know why you would want to.

function penis() {
    console.log('poo bar');
};

const testicle = penis;

console.log(testicle.name)// 'penis';
testicle();// 'poo bar'
penis();// 'poo bar'

(This rest of this section is copied from http://stackoverflow.com/a/336868).

The difference is that functionOne is defined at run-time, whereas functionTwo is defined at parse-time for a script block. For example:

<script>
  // Error
  functionOne();

  const functionOne = function() {
  };
</script>

<script>
  // No error
  functionTwo();

  function functionTwo() {
  }
</script>

This also means you can't conditionally define functions using the second syntax:

<script>
  if (test) {
     // Error or misbehavior
     function functionThree() { doSomething(); }
  }
</script>

The above actually defines functionThree irrespective of test's value — unless use strict is in effect, in which case it simply raises an error.

Parameters & Arguments

First off, a parameter is a variable that is part of a functions signature (function declaration), while an argument is an actual value passed to a function when calling it (think "actual argument" vs "formal parameter").

In JavaScript, a function does not need to have any parameters defined to allowing passing arguments to it. All arguments passed to a function are accessible through the special arguments array-like variable inside the function body.

function hasParameters(poo, far, and, succeed) {
    console.log(poo);
    console.log(far);
    console.log(and);
    console.log(succeed);

    console.log(arguments[0]);
    console.log(arguments[1]);
    console.log(arguments[2]);
    console.log(arguments[3]);
}

function lacksParameters() {
    console.log(arguments[0]);
    console.log(arguments[1]);
    console.log(arguments[2]);
    console.log(arguments[3]);
}

hasParameters(1, 2, 3);// 1 2 3 undefined 1 2 3 undefined lacksParameters(1, 2, 3);// 1 2 3 undefined 1 2 3 undefined

Scopes

JavaScript is lexically scoped, but only function blocks create a new scope (not if or for blocks for example). (The new let and const variables are lexically scoped)

Since functions can be nested inside each other, several degrees of locality can be created. Each local scope can see all scopes which contains it.

function() {
    const testicle = 'one ball';

  function() {
    const balls = 'two balls';
    console.log(testicle);
    console.log(balls);
  }
}
console.log(testicle); // ReferenceError

this

One of the few tricky things with JavaScript is to understand how this is bound during function calls.

const obj = {
    fnc: function() {
        console.log(this === obj);
        console.log(this === window);
    }
};

const fnc = obj.fnc;

obj.fnc();// true false
fnc();// false true

Function.prototype.bind(thisArg)

Returns a new function which is bound to thisArg and has "prefilled" arguments. Very similar to LoDash' _.partial, except that partial does not alter the this binding.

Function.prototype.call(thisArg, ...args)

Calls a function with this bound to thisArg and args as arguments. Essentially the same as

fnc.call(obj, arg1, arg2);

// is the same as

const boundFnc = fnc.bind(obj);

boundFnc(arg1, arg2);

Function.prototype.apply(thisArg, args)

Similar to call but takes an array of arguments, instead of the arguments seperately.

Used to be useful if you had an array of unkown length that you wanted to use as arguments in a function call.

function org(adverb, verb, noun) {
    console.log(`I'm going to ${adverb} ${verb} your ${noun}`);
}

function ext() {
    // do something
    org.apply(this, arguments);
}

With the advent of spread operator we rarely need .apply anymore

function org(adverb, verb, noun) {
    console.log(`I'm going to ${adverb} ${verb} your ${noun}`);
}

function ext(...args) {
  args[2] = 'balls';

    org(...args);
}

ext('gently', 'caress');

Arrow Functions

Arrow functions are a terse way to define anonymous functions. They are identical to normal functions in all other ways except one; this is inherited from the surrounding scope and cannot be rebound.

IIFE (Immediately Invoked Function Express)

IIFEs are functions that are immediately invoked and are mostly used to create scopes.

(function() {
    const secretTesticle = 'another ball';

    console.log(secretTesticle);
})();

Notice the brackets at the end. The following snippet (which does exactly the same thing) might be a little clearer:

const fnc = function() {
    const secretTesticle = 'another ball';

    console.log(secretTesticle);
}

fnc();

results matching ""

    No results matching ""