-3

I use the "Lazy Function Definition" pattern to define global functions like so:

if (bArmingSequenceComplete () ) {
    console.log ("Good to go.");
}
// Code flows from high level to low level and support functions...
// vvvvv

function bArmingSequenceComplete () {
    //  In reality this is a long, complicated series of tests that only need to be done once.
    var gtg = true;  

    if (gtg) {
        bArmingSequenceComplete  = function () { return true; };
    }
    else {
        bArmingSequenceComplete  = function () { return false; };
    }

    return bArmingSequenceComplete ();
}

This works flawlessly and the overall code is easy to grok.
I like this pattern because it's very efficient AND it's clear as to what it's doing.

But JSHint gives me warnings like:

Reassignment of 'bArmingSequenceComplete', which is is a function. Use 'var' or 'let' to declare bindings that may change.

After diving into some JSHint source code, I found that this is controlled by the W021 option. So I can squelch it like:

    // jshint -W021
    if (gtg) {
        bArmingSequenceComplete  = function () { return true; };
    }
    else {
        bArmingSequenceComplete  = function () { return false; };
    }
    // jshint +W021

But, is JSHint telling me something useful? Is it really a mistake to define such functions?

Can I disable all such warnings globally without also losing the general "Reassignment" check?


The suggestions to use let or var make for worse code (violates "Most important at top" rule and/or completely fails).

For example:

if (bArmingSequenceComplete () ) {
    console.log ("Good to go.");
}

// Code flows from high level to low level and support functions...
// vvvvv

let bArmingSequenceComplete = function  () {
...

Fails with:

Uncaught ReferenceError: bArmingSequenceComplete is not defined


And:

if (bArmingSequenceComplete () ) {
    console.log ("Good to go.");
}

// Code flows from high level to low level and support functions...
// vvvvv

var bArmingSequenceComplete = function  () {
...

Fails with:

Uncaught TypeError: bArmingSequenceComplete is not a function


Defining the function before use, violates the boss's "most important or high-level up top" rule.

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • 1
    change first line to `let bArmingSequenceComplete = function () {` – Jaromanda X Nov 23 '17 at 04:48
  • @JaromandaX, turns out that doesn't work well. See the updated question. – Brock Adams Nov 23 '17 at 05:56
  • use var not let? – Jaromanda X Nov 23 '17 at 05:59
  • @JaromandaX, Fails with "is not a function". See the last code block. – Brock Adams Nov 23 '17 at 05:59
  • Why not use `IIFE` pattern here? – guleria Nov 23 '17 at 06:02
  • Late comment, but rather than reassigning the function, which is a code smell, might you keep a persistent variable the function can see, and on call, return that variable if it exists, otherwise run the expensive procedure (once) and reassign that persistent variable? Disadvantage is that if you want the result to be encapsulated in the function, you'll have to create its scope in advance https://jsfiddle.net/1put6ks9/ – CertainPerformance Oct 03 '18 at 00:10
  • Thanks, @CertainPerformance, that's a possibility, but I don't like breaking encapsulation. Anyway, I've since switched to a better validator than JSHint -- which may be the best answer to this problem. – Brock Adams Oct 03 '18 at 00:30

1 Answers1

-1

IMHO, Using the IIFE pattern can come in handy in your case. EG:

let bArmingSequenceComplete = (function () {
    let gtg = true;
    let outputMethod = null;
    if (gtg) {
        outputMethod = () => { return true; };
    } else {
        outputMethod = () => { return false; };
    }
    return outputMethod;
})();

if(bArmingSequenceComplete()) {
    console.log('good to go');
}

Update:

Since there are 2 conditions you need:

  • Define high-level code at the top
  • Define support/helper methods at bottom

So let's try it this way:

function startHighLevelCode() {
    if(bArmingSequenceComplete()) {
        console.log('good to go');
    }
}

let bArmingSequenceComplete = function () {
    let gtg = true;
    let outputMethod = null;
    if (gtg) {
        outputMethod = () => { return true; };
    } else {
        outputMethod = () => { return false; };
    }
    bArmingSequenceComplete = outputMethod;
    return bArmingSequenceComplete();
};

// After all support functions
startHighLevelCode();
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
guleria
  • 741
  • 2
  • 11
  • 23
  • Thanks, guleria, but notice that this buries the "high level" code (EG: `if(bArmingSequenceComplete(...`) underneath all the support functions. – Brock Adams Nov 23 '17 at 06:11
  • Also, it fires the very expensive `bArmingSequenceComplete()` code whether it needs it or not. – Brock Adams Nov 23 '17 at 06:13
  • @BrockAdams I updated the answer. Have a look if this satisfies your criteria. It is a workaround but looks good I think. – guleria Nov 23 '17 at 07:04
  • My bad I had forgotten the `return bArmingSequenceComplete();` at the end of `bArmingSequenceComplete` method. Updated it. – guleria Nov 23 '17 at 07:14