DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for Javascript Tricks
Edison Sanchez
Edison Sanchez

Posted on • Updated on

Javascript Tricks

How to check null value and undefined to get a nested object's property?

nullish and chain operators

 const product = {
    name: 'Coke',
    price: 10,
    provider: {
      name: 'Wailkk',
      address: 'Fake Street',
      state: {
        id: 1,
        name: 'Florida',
        country: {
          code: 'US',
          name: 'United States',
        },
      },
      orders: null,
      fPrice: (x) => 100,
    },
  };

  //Old way
  const providerCountry = product.provider
    ? product.provider.name
      ? product.provider.name
      : null
    : null;

  //Nullish Coalsencing Operator Way
  //If the value is null then this option it will not works.
  const _providerCountry = product.provider.name ?? undefined;

  //Not work if the value is null
  const providerOrders = product.provider.orders ?? 1;
  // Should be null.  [Error]

  // Nullish not defined.
  const providerNotDefined = product.provider.notDefined ?? null;

  //Trick: chaining Operator
  const providerAddress = product?.provider?.address;

  //It works with Dynamic properties.
  const propertyName = 'price';
  const productPrice = product?.[propertyName]?.explore;

Chain Operator Way

If a property doesn't exist or value is undefined then will returns undefined, keeping your code clean. If a property doesn't exist undefined will be returned. Let's see how this operator looks with the same example object:

  //Trick: chaining Operator
  const providerAddress = product?.provider?.address;

  //It works with Dynamic properties.
  const propertyName = 'price';
  const productPrice = product?.[propertyName]?.explore;

  //Works with Functions too.
  const productProviderPrice = product?.provider?.fPrice?.('x');
  //Result: 100;

  const _productProviderPrice = product?.provider?.fPricex?.('x');
  //Result: undefined

NOT Compatible with: Internet Explorer, Firefox for Android, Opera for Android, and Samsung Internet Browser.


IIFE: Immediately-Invoked Function Expression

It's a function invoked immediately after it is defined (as the name says).

let hi = (() => {
  return 'Hello Dear World';
})();
//Define function and parenthesis before the semicolon.

console.log(hi); 
// Result = 'Hello Dear World'

Function Closures

Combination of functions stacked or bundled together with access over outer layers or outer function's scope.

const functionLevelOne = () => {
  let day = 23;

  const functionLevelTwo = () => {
    day += 1;
    return day;
  }

  return functionLevelTwo;
}

console.log(functionLevelOne());
// Result: 24;
// It's calling the return function on level one.

When to use spread operators?

Merge two arrays using spreads could impact on performance if it's a repetitive call. And if we call a function passing arguments like spread and that call is frequently. Use ...spread only when it's not a repetitive call or for a function's call but not as argument spread definition.

I will keep adding and updating tricks to this article frequently.

Find and Filtering

  • Find a record for key value:
let colors = [
  { id: 0, color: 'Red' },
  { id: 1, color: 'Green' },
  { id: 2, color: 'Blue' }
];
let greenColor = colors.find(color => color.color === 'Green');

Filter Records by id value

let users = [
  { id: 0, name: 'John Smith' },
  { id: 1, name: 'Mary Smith' },
  { id: 2, name: 'Jane Foster' }
];

let filteredData = data.filter(path => path.includes('Smith'));

Returns the name of users with the last name 'Smith'.

Iterations

Iterate between key,values for an object.

let myObject = { one: 1, two: 2, three: 3 };
Object.keys(myObject).forEach((key, value) => {
  //...do something
  console.log(key, value);
});

Event Loop Essentials.

A Task queue is used by Javascript. Javascript tasks have the highest priority. Micro Tasks like promises have the second priority position; third place for Macro Tasks executed before (requestAnimationFrame) or after (setTimeout) to render.

console.log(1);
Promise.resolve().then(() => console.log(2));
setTimeout(() => console.log(3), 100);
console.log(4);
// 1 -> 4 -> 2 -> 3

There are three ways to add your callback function(s) to the DOM element as the event callback.

  • InLine (Higher Priority)

    <div onclick="console.log('div')">Hello</div>
    
  • Bind Callback (Medium Priority)

    div.onclick = () => console.log('div');
    
  • Add/Remove Event Listener: Supports Multiple Callbacks associated with the same event. Supports Event bubbling and capturing.

    div.addEventListener('click', callbackOne);
    div.removeEventListener(callbackOne);
    

Bubbling

<div onclick="console.log('div')">
  <p onclick="console.log('p')">
    <span onclick="console.log('span')">
    </span>
  </p>
</div>
//span β†’ p β†’ div

Bubbling: The innermost element β†’ the second innermost element β†’ … β†’ the outermost element
Capturing: The outermost element β†’ the second outermost element β†’ … β†’ the innermost element

Capturing is triggered earlier than bubbling

div.addEventListener('click', () => console.log('div'));
p.addEventListener('click', () => console.log('p'), { capture: true });
span.addEventListener('click', () => console.log('span'));
//Result: p β†’ span β†’ div

div and span use bubbling, and p uses capturing.

Event Delegation

If you have a loop function with multiple callbacks that will affects the performance:

const ul = document.getElementById('myUL');
for (let i = 0; i < 100; i += 1) {
  const li = document.createElement('li');
  li.textContent = `li-${i}`;
  li.id = `li-${i}`;
  li.addEventListener('click', e => console.log(e.target.id));
  ul.appendChild(li);
}

Delegate one callback for all.

const ul = document.getElementById('myUL');
for (let i = 0; i < 100; i += 1) {
  const li = document.createElement('li');
  li.textContent = `li-${i}`;
  li.id = `li-${i}`;
  ul.appendChild(li);
}
ul.addEventListener('click', e => console.log(e.target.id));

Event Propagation

Stop propagation makes a halt to the propagation used by bubbling or capturing.

div.addEventListener('click', () => console.log('div'), true);
p.addEventListener('click', e => {
  e.stopPropagation();
  console.log('p');
});
span.addEventListener('click', () => console.log('span'), true);

When user clicks

only will be logged 'p'.

XMLHttpRequest

Oldest fetch data in an asynchronous way

const oReq = new XMLHttpRequest();
oReq.open('GET', 'https://jsonplaceholder.typicode.com/todos/1');
oReq.send();
oReq.addEventListener('load', function () {
  console.log(this.responeText);
});

Fetch

New way with more options than XMLHttpRequest, returns a promise

// Promise
fetch(url)
  .then(res => res.json())
  .then(data => console.log(data));
// async & await
const res = await fetch(url);
const data = await res.json();
console.log(data);

Axios

It takes the best of XMLHttpRequest and fetch.

// Promise 
axios.get('/user?ID=12345')
  .then(function (response) {
    // handle success
    console.log(response);
  })
  .catch(function (error) {
    // handle error
    console.log(error);
  })
  .finally(function () {
    // always executed
  });
// async & await
async function getUser() {
  try {
    const response = await axios.get('/user?ID=12345');
    console.log(response);
  } catch (error) {
    console.error(error);
  }
}

Top comments (1)

Collapse
 
jonrandy profile image
Jon Randy πŸŽ–οΈ

Your "Function Closures" example returns the functionLevelTwo function, not 24

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.