Lesson 51: Mastering JavaScript Function Objects & NFE with challenges!

manoj ymkmanoj ymk
5 min read

๐Ÿง  What is a Function in JavaScript?

In JavaScript, functions are first-class objects. This means:

  • They can be stored in variables.

  • They can be passed as arguments to other functions.

  • They can be returned from functions.

  • They can have properties and methods, just like any other object.

โœ… Functions are "callable objects" with internal [[Call]] and optional [[Construct]] behaviors.


๐Ÿงช Examples

function greet(name) {
  return `Hello, ${name}`;
}

greet.language = 'English';

console.log(greet('Manoj'));        // Hello, Manoj
console.log(greet.language);        // English (property on function)

๐Ÿ” Function Properties

name (Read-only)

Auto-assigned based on declaration or contextual naming.

let f = function custom() {};
console.log(f.name); // "custom"

Even anonymous functions can have a contextual name:

let greet = function() {};
console.log(greet.name); // "greet"

length

Returns the number of formal parameters (excluding rest parameters and defaults).

function f(a, b, ...rest) {}
console.log(f.length); // 2

๐Ÿ”น 2. Fill Any Gaps

๐Ÿ”ฌ Internal Mechanics

Functions have internal slots:

  • [[Environment]]: lexical scope

  • [[Code]]: function body

  • [[ThisMode]]: controls how this is resolved (lexical, strict, global)

๐Ÿชค Common Misconceptions

  • Not all function expressions have names.

  • function foo() {} is a Function Declaration. But:

      let bar = function foo() {}; // is an Expression
    
  • func.name inside an anonymous function is not always empty โ€” JS engines often infer it.


โš ๏ธ Behavior in Strict Mode

"use strict";
function f(a, a) {} // โŒ SyntaxError in strict mode

๐Ÿงฑ Function Object vs Closure Variable

function makeCounter() {
  function counter() {
    return counter.count++;
  }
  counter.count = 0;
  return counter;
}

Here, .count is attached to the function object, not its closure.

โœ… Alternative: closure-based encapsulation.


๐Ÿง  Named Function Expression (NFE)

NFE enables safe recursion inside assigned functions:

let sayHi = function func(who) {
  if (!who) return func("Guest");
  console.log(`Hello, ${who}`);
};

Why not just call sayHi() inside? Because sayHi could be reassigned or nulled externally. func is only visible inside the function body.


๐Ÿ”น 3. Challenge Me Deeply

๐ŸŸข Basic

  1. Create a function add with a .count property that tracks how many times it was called.

  2. Write a function that logs its name and length.

  3. Define a function with rest parameters and show how length behaves.

๐ŸŸก Intermediate

  1. Write a memoize(fn) utility that caches function calls by attaching .cache to the function.

  2. Create a function object with helper functions attached (like _.isArray, _.isNumber).

  3. Build a polyfill checker using globalThis and Function.name to log unsupported functions.

๐Ÿ”ด Advanced

  1. Create a recursive NFE that finds the factorial, and safely works even if reassigned.

  2. Implement a rate-limited function with .lastCalledTime as a function property.

  3. Emulate private state using closure vs function property โ€” then compare memory exposure.

  4. Write a meta-function that accepts any function and logs its .name and .length, then calls it.

๐ŸŽฏ Bonus Brain-Twister

What will be logged?

let sayHi = function func(who) {
  if (!who) return func("Guest");
  console.log(`Hello, ${who}`);
};

let welcome = sayHi;
sayHi = null;
welcome();

๐Ÿ”น 4. Interview-Ready Questions

๐Ÿ“˜ Conceptual

  • Why are functions considered objects in JavaScript?

  • What is the purpose of a Named Function Expression?

๐Ÿ’ก Scenario

  • How would you build a logger that tracks how often a function is used?

  • When would you use a function property instead of a closure?

๐Ÿงฉ Debugging

  • Why is this code failing?
let sayHi = function(who) {
  if (!who) sayHi("Guest");
};
let welcome = sayHi;
sayHi = null;
welcome(); // โŒ Error

โœ… Best Practices

  • โœ… Prefer closures for encapsulated state

  • โœ… Use .name and .length for debugging tools

  • ๐Ÿšซ Avoid relying on contextual names for production logic


๐Ÿ”น 5. Real-World Usage

  • jQuery: $ is a function object with many attached helpers ($.ajax, $.extend)

  • Lodash: _ is a function with attached methods like _.map, _.filter

  • Event systems: addEventListener(fn) โ†’ tracking functions via .id or metadata

  • Analytics: Function wrappers that log .name or timing


๐Ÿ”น 6. Remember Like a Pro

๐Ÿง  Mnemonic

F.L.I.P. โ€” Key Function Properties

  • F = Function

  • L = length of parameters

  • I = Internal name (NFE)

  • P = Properties attached (counter, id, etc.)


๐Ÿ“Œ Cheatsheet

PropertyTypeDescription
nameStringInferred or defined function name
lengthNumberNumber of declared parameters (excl. rest)
CustomAnyYou can add anything: .counter, .meta, etc.

๐Ÿ”น 7. Apply It in a Fun Way

๐ŸŽฏ Mini Project: Function Tracker Utility

Goal: Track function invocations, durations, and arguments.

๐Ÿ›  Steps:

  1. Create a function track(fn) that wraps any function.

  2. Store call count, duration, and arguments on the wrapper.

  3. Attach .log() to view the history.

function track(fn) {
  function wrapper(...args) {
    wrapper.calls.push(args);
    return fn.apply(this, args);
  }
  wrapper.calls = [];
  wrapper.log = () => console.log(wrapper.calls);
  return wrapper;
}

const sum = track((a, b) => a + b);
sum(1, 2);
sum(3, 4);
sum.log(); // [[1, 2], [3, 4]]

๐ŸŽฎ Extend It Further:

  • Track average duration

  • Detect slow functions

  • Group by .name


โž• Extra Value

๐Ÿ” Projects That Use This

  • Lodash, Underscore.js

  • Express middleware functions often use .length for introspection

  • Mocha, Jest sometimes attach properties to test callbacks

โš ๏ธ Common Mistakes

  • Assuming length includes rest parameters

  • Using external variable names for recursion

  • Modifying function identity (e.g., sayHi = null) without understanding the consequences

๐Ÿงฐ Performance Tips

  • Avoid bloating function objects with too many properties in tight loops

  • Use closures for hidden state to avoid external mutation

  • Prefer named function expressions for self-reference

0
Subscribe to my newsletter

Read articles from manoj ymk directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

manoj ymk
manoj ymk