DEV Community

Cover image for JavaScript Prototyping: Extending Built-in Objects with Custom Functions
Alex Aslam
Alex Aslam

Posted on • Edited on

JavaScript Prototyping: Extending Built-in Objects with Custom Functions

JavaScript's prototype system is one of its most powerful (and sometimes misunderstood) features. It allows you to add new methods and properties to existing objects, including native types like Arrays, Numbers, and Objects. In this guide, we'll explore how prototyping works and demonstrate practical examples of extending built-in objects.

Understanding JavaScript Prototypes

Every JavaScript object has a hidden [[Prototype]] property that links to another object. When you try to access a property that doesn't exist on an object, JavaScript looks up the prototype chain until it finds the property or reaches null.

The Prototype Chain

const arr = [1, 2, 3];
console.log(arr.__proto__ === Array.prototype); // true
console.log(Array.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
Enter fullscreen mode Exit fullscreen mode

Extending Built-in Objects

While extending native prototypes is controversial (it can cause conflicts in large codebases), it can be useful for utility functions you use frequently.

1. Adding a Method to Arrays

Let's create a sum() method for arrays:

Array.prototype.sum = function() {
  return this.reduce((total, num) => total + num, 0);
};

const numbers = [1, 2, 3, 4];
console.log(numbers.sum()); // 10
Enter fullscreen mode Exit fullscreen mode

2. Adding a Method to Numbers/Integers

We can add a square() method to all numbers:

Number.prototype.square = function() {
  return this * this;
};

const num = 5;
console.log(num.square()); // 25
Enter fullscreen mode Exit fullscreen mode

3. Adding a Method to Objects

Let's add a deepClone() method to all objects:

Object.prototype.deepClone = function() {
  return JSON.parse(JSON.stringify(this));
};

const original = { a: 1, b: { c: 2 } };
const clone = original.deepClone();
clone.b.c = 3;
console.log(original.b.c); // 2 (unchanged)
Enter fullscreen mode Exit fullscreen mode

Best Practices for Prototyping

  1. Check for Existing Methods First
   if (!Array.prototype.sum) {
     Array.prototype.sum = function() { /* ... */ };
   }
Enter fullscreen mode Exit fullscreen mode
  1. Use Object.defineProperty for Non-Enumerable Methods
   Object.defineProperty(Array.prototype, 'sum', {
     value: function() { /* ... */ },
     enumerable: false // Won't show up in for...in loops
   });
Enter fullscreen mode Exit fullscreen mode
  1. Consider Alternatives For shared code, consider utility functions instead:
   function sumArray(arr) {
     return arr.reduce((t, n) => t + n, 0);
   }
Enter fullscreen mode Exit fullscreen mode

Advanced Example: Chaining Custom Methods

Array.prototype.square = function() {
  return this.map(n => n * n);
};

Array.prototype.average = function() {
  return this.sum() / this.length;
};

const results = [1, 2, 3].square().average();
console.log(results); // 4.666... (average of [1, 4, 9])
Enter fullscreen mode Exit fullscreen mode

When Not to Modify Prototypes

  1. In large team projects where naming conflicts might occur
  2. When working with third-party libraries that might expect default behavior
  3. For properties/methods that might become native JavaScript features in the future

Conclusion

JavaScript's prototype system offers powerful capabilities for extending built-in objects. While you should use this feature judiciously, understanding prototypes is crucial for advanced JavaScript development. Whether you choose to extend native prototypes or create utility functions, the prototype chain remains fundamental to how JavaScript works.


Feel Free To Ask Questions, Happy coding! 🚀

Top comments (0)