简体   繁体   中英

Allow other JavaScript functions (including from other files) to “hook” into my function

I feel like I'm overthinking this concept, but I'm stuck on it. Does JavaScript have the ability to allow other functions (from the same or different JS files) to hook into a function?

To clarify, if I create an array in a function I am writing is it possible to allow other JS files to hook into it to modify that array before I parse it? Or would I need to build some kind of system to manage all of the "hooks"? I'd like to avoid using a global window variable if possible, but that would work.

Here's an example

For sake of argument, let's assume these run in the order I've listed them (ignore the race condition I've created here).

main.js

var animals = ['cat', 'dog'];
animals = hookIntoThis(animals); //Allow other functions or files to add/modify animals to the array here
console.log(animals); //--> "cat", "dog", "elephant"

hookIntoThis() is not actually a reference to anything- that would just be where I'd want to let other functions/files (if they exist) modify the array.

other.js

function addMoreAnimals(animals){ //This would somehow listen for that hook from main.js
    animals.push('elephant');
    animals.push('lion');

    return animals;
}

whatever.js

function noLions(animals){ //This would also hook into that function from main.js to modify the array
    if ( animals.indexOf('lion') >= 0 ){
        animals.splice(animals.indexOf('lion'), 1); //Just for the sake of example
    }

    return animals;
}

At first I was thinking a custom DOM event/listener would work, but that is (as far as I know) a one-way thing. I could trigger, and even pass the animals array to the DOM event, but unless I use a global window variable I couldn't get any data back .

I apologize if this is an overly simple concept and/or a duplicate question. I did search around quite a bit before posting this.

The custom event listener is the right one, I think, if main doesn't know which other modules are going to be modifying animals .

If you know that all hooks will be executed synchronously, you can have main do its main work (after modification) in a microtask, once the main thread has finished, eg:

 // main.js let modifiableAnimals = ['cat', 'dog']; window.addEventListener('customHook', ({ detail: modifyFn }) => { modifiableAnimals = modifyFn(modifiableAnimals); }); Promise.resolve() .then(() => { console.log(modifiableAnimals); }); // other.js window.dispatchEvent( new CustomEvent( 'customHook', { detail: (animals) => { animals.push('elephant'); animals.push('lion'); return animals; } } ) ); // whatever.js window.dispatchEvent( new CustomEvent( 'customHook', { detail: (animals) => { if ( animals.indexOf('lion') >= 0 ){ animals.splice(animals.indexOf('lion'), 1); //Just for the sake of example } return animals; } } ) ); 

If you know that the existing array is only going to be mutated (and doesn't have to be reassigned), you can simplify it a bit:

 // main.js const modifiableAnimals = ['cat', 'dog']; window.addEventListener('customHook', ({ detail: modifyFn }) => { modifyFn(modifiableAnimals); }); Promise.resolve() .then(() => { console.log(modifiableAnimals); }); // other.js window.dispatchEvent( new CustomEvent( 'customHook', { detail: (animals) => { animals.push('elephant'); animals.push('lion'); } } ) ); // whatever.js window.dispatchEvent( new CustomEvent( 'customHook', { detail: (animals) => { if ( animals.indexOf('lion') >= 0 ){ animals.splice(animals.indexOf('lion'), 1); //Just for the sake of example } } } ) ); 

This is still kind of weird to do though, IMO. If possible, I'd consider having something else interface with main.js and the other files, and call main.js functions with the handlers instead:

 // main.js function changeAnimals(...changeFns) { const modifiableAnimals = ['cat', 'dog']; changeFns.forEach(fn => fn(modifiableAnimals)); console.log(modifiableAnimals); } // other.js const pushElephantAndLion = (animals) => { animals.push('elephant'); animals.push('lion'); }; // whatever.js const removeOneLion = (animals) => { if ( animals.indexOf('lion') >= 0 ){ animals.splice(animals.indexOf('lion'), 1); //Just for the sake of example } }; // *actual* main code: changeAnimals(pushElephantAndLion, removeOneLion); 

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