DEV Community

artydev
artydev

Posted on

Closures in Javascript

Closures allow returned inner functions to capture variables defined in outer functions (light definition)

They are useful when used as private variables, or don't want to pollute global namespace.

Here are two examples of some of my previous posts :

Counters

// https://github.com/ai/nanoid
//A tiny, secure, URL-friendly, unique string ID generator for JavaScript.
let nanoid=(t=21)=>crypto.getRandomValues(new Uint8Array(t)).reduce(((t,e)=>t+=(e&=63)<36?e.toString(36):e<62?(e-26).toString(36).toUpperCase():e>62?"-":"_"),"");

function Counter () {
  let count = 0
  function View () {
    let uuid = nanoid()  
    let div = document.createElement("div")
    div.innerHTML = `
      <h1 id=display-${uuid}>${count}</h1>
      <button id=counter-${uuid}>CLICK</button>
    `
    let target = div.querySelector(`#display-${uuid}`) 
    let btn = div
      .querySelector(`#counter-${uuid}`)
      .onclick =  () => target.innerText = ++count 
    return div
  }
  return View ()
}

[...Array(5)].forEach(() => document.body.append(Counter()))
Enter fullscreen mode Exit fullscreen mode

Here is an updated version, thanks Eckehard

RotatingImages

// allow pausing while rotate
function sleep(ms = 0) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

// returns an object containing the closure and the refrenced image
function rotateImage (id) {
  let angle = 0;
  let prevangle = 0
  let img = document.getElementById(id);
  async function _rotateImg () {
    while (angle < prevangle + 90) {
      angle += 19;
      await sleep(0)
      img.style.transform = `rotate(${angle}deg)` ;
    }
    let rest = angle % 90;
    // increment is not a divisor of 90
    // we adjust the rotation
    if (rest > 0) {
      while (rest > 0) {
         rest -= 1
        await sleep(0)
        img.style.transform = `rotate(${--angle}deg)` ;
      }
    }
    img.dataset.angle = angle
    prevangle = angle
    checkImages()
  }
  return { rotator: _rotateImg, image:img } ;
}

// we check if all images are in nomal position
function checkImages () {
  let aligned = [imagegRotator, imagegRotator2].reduce( 
    function check (acc,imgrot) {
      return  (imgrot.image.dataset.angle % 360 === 0) && acc
   }
 , true);
 if (aligned) { 
   message.innerText = ("We are two cutes American Pit Bull Terrier")
 }
 else {
    message.innerText = ""
 }
}

function main () {
  // we have to declare those variable as globals
  // to attach onclick events
  window.imagegRotator = rotateImage("image");
  window.imagegRotator2 = rotateImage("image2");
  checkImages ()
  console.log(Object.keys(imagegRotator));

}

main()
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
efpage profile image
Eckehard

Good explanation! Just fiddeling around with global id´s (even if you use uuid´s) is a bit contraproductive in this case. I would prefer to keep all references local, which makes the code much cleaner.

Example