Skip to main content

Default Function Properties – Complete Guide to Function's Built-In Variables

Default function properties are the built-in variables available in every function declaration.

In other words, JavaScript, by default, adds the following six (6) properties to your function declarations:

  • arguments
  • caller
  • length
  • name
  • prototype
  • [[Prototype]] (also known as __proto__ or dunder proto)

Here's an example:

// Declare a function on the Firefox browser's console:
function play() {}

// Call the play function:
play;

// The call above will return:
function play():
arguments: null
caller: null
length: 0
name: "play"
prototype: Object {...}
[[Prototype]]: function()

Video: Demo of the 6 default function properties in JavaScript.

You can see that the browser returned the play function containing six (6) properties:

  • arguments
  • caller
  • length
  • name
  • prototype
  • [[Prototype]]

Let's discuss the six default properties now.

What Is the Default arguments Property in JavaScript Functions?

JavaScript uses the arguments property to encase all the arguments (values) you pass to a function's parameters through the function's invocator.

Note the following:

  • The arguments property's value is an array-like object containing a list of the function's arguments (parameters' values).
  • The arguments object also contains default properties such as callee and Symbol(Symbol.iterator).

Here's an example:

// Define a function:
function listBodyParts(part1, part2) {
return arguments;
}

// Invoke the listBodyParts function while passing some values to its parameters:
listBodyParts("Eye", "Leg");

// The invocation above will return:
// ["Eye", "Leg", callee: ƒ, Symbol(Symbol.iterator): ƒ]

// Note: Some browser's output may look like so:
// { 0: "Eye", 1: "Leg", callee: ƒ, length: 2, Symbol(Symbol.iterator): ƒ}

The snippet above returned the arguments property's value (an array-like object containing a list of arguments).

Here's another example:

// Define a function:
function knowMyBody(part1, part2) {
return `My ${arguments[1]} has an ${arguments[0]}!`;
}

// Invoke the knowMyBody function while passing some values to its parameters:
knowMyBody("Eye", "Leg");

// The invocation above will return:
// "My Leg has an Eye!"

Try Editing It

The snippet above used some of the arguments property's values as part of the returned sentence's variables.

What Is the Default caller Property in JavaScript Functions?

Deprecated feature

JavaScript has deprecated the caller property. So, avoid using it. It may stop working at any time. This section exists for reference purposes only.

caller references the function that invoked the property's function.

Here's an example:

// Define a function:
function checkManager() {
return checkManager.caller;
}

// Define another function:
function checkPresident() {
return checkManager();
}

// Invoke the checkPresident function above:
checkPresident();

// The invocation above will return:
function checkPresident() {
return checkManager();
}

checkPresident() invoked the checkManager() function in the snippet above. Therefore, the caller property referenced checkPresident().

The caller property will return null for strict, async function, and generator function callers.

Here's an example:

// Define a function:
function checkManager() {
return `${checkManager.caller} called the checkManager function.`;
}

// Define another function:
function checkPresident() {
"use strict";
return checkManager();
}

// Invoke the checkPresident() function above:
checkPresident();

// The invocation above will return:
// "null called the checkManager function."

The caller property returned null because checkPresident() invoked checkManager() in strict mode.

What Is the Default length Property in JavaScript Functions?

JavaScript uses the length property to indicate the function's total number of regular parameters.

Here's an example:

// Define a function:
function checkParameter(p1, p2, p3, p4) {
return `This function has ${checkParameter.length} parameters.`;
}

// Invoke the checkParameter function:
checkParameter();

// The invocation above will return:
// "This function has 4 parameters."

Try Editing It

The length property ignores non-regular parameters like the rest parameter. For instance, consider the following code:

// Define a function:
function checkParameter(p1, p2, p3, ...p4) {
return `This function has ${checkParameter.length} parameters.`;
}

// Invoke the checkParameter function above:
checkParameter();

// The invocation above will return:
// "This function has 3 parameters."

Try Editing It

The length property returned 3 because it ignores irregular parameters like the rest parameter (...p4).

What Is the Default name Property in JavaScript Functions?

JavaScript uses the name property to record the function's name as defined at its creation.

Here's an example:

// Define a function:
function checkName() {
return `This function's name is: ${checkName.name}.`;
}

// Invoke the checkName function:
checkName();

// The invocation above will return:
// "This function's name is: checkName."

Try Editing It

Browsers may use an empty string as an anonymous function's name.

Here's an example:

// Invoke an anonymous function's name:
(function () {}).name;

// The invocation above will return: ""

What Is the Default prototype Property in JavaScript Functions?

The prototype property stores the features a function will share with its object instances.

In other words, whenever you use the new operator to construct a new object from an existing function. In that case, JavaScript will share the function's prototype property with the newly created object.

tip

Whatever function you call with the new keyword becomes a constructor function.

For instance, the new createBook code below makes createBook a constructor function.

function createBook() {}
const book1 = new createBook();
console.log(book1);

Try Editing It

The snippet above used the new keyword to construct a new object from createBook(). Therefore, the book1 object is an instance of the createBook() constructor function.

JavaScript shares only the features you define in a constructor function's prototype property with the constructor's object instances. It does not share other items, such as the statements in the function's body.

For instance, the Array() constructor function has some default properties. However, any new object you create with the new Array() syntax will inherit only the items in the prototype property.

Video: The demo uses JavaScript Array to show you an example of the prototypal inheritance.

Below are eight essential facts to remember about the prototype property.

1. The return operator does not cause objects to inherit prototype

Objects that functions produce with the return keyword do not inherit the prototype property.

For instance, consider the following code:

// Define a function:
function companyProfile() {
return {};
}

// Create an object based on the companyProfile() function:
const bestWebsite = companyProfile();

// Check bestWebsite's content:
bestWebsite;

// The invocation above will return: {}

In the snippet above,

  • bestWebsite's content is an object that companyProfile() produced with the return keyword.

Let's see what will happen if we store a property in the companyProfile()'s prototype.

// Add a property to the companyProfile's prototype:
companyProfile.prototype.name = "CodeSweetly";

// Invoke the name property from the bestWebsite object:
bestWebsite.name;

// The invocation above will return: undefined

Try Editing It

The snippet above returned undefined because of the following reasons:

  1. JavaScript could not find a name property in the bestWebsite object.
  2. bestWebsite did not inherit the companyProfile's prototype because it is a returned object.

You can make bestWebsite inherit companyProfile's prototype by creating the object with the new operator like so:

// Define a function:
function companyProfile() {}

// Create an object based on the companyProfile() function:
const bestWebsite = new companyProfile();

// Check bestWebsite's content:
bestWebsite;

// The invocation above will return: {}

In the snippet above,

  • bestWebsite's content is an object that companyProfile() produced with the new keyword.

Let's see what will happen if you store a property in the companyProfile()'s prototype.

// Add a property to the companyProfile's prototype:
companyProfile.prototype.name = "CodeSweetly";

// Invoke the name property from the bestWebsite object:
bestWebsite.name;

// The invocation above will return: "CodeSweetly"

Try Editing It

The snippet above returned "CodeSweetly" because of the following reasons:

  1. The new keyword caused the bestWebsite object to inherit the companyProfile's prototype property.
  2. companyProfile's prototype has a name property which bestWebsite also inherited.

2. An object is prototype's default value

The prototype property's default value is an object containing constructor and [[Prototype]] properties.

For instance, consider the following code:

// Define a function:
function companyProfile() {}

// Check the companyProfile's prototype property's content:
companyProfile.prototype;

// The invocation above will return:
// {...}:
// constructor: function companyProfile()
// [[Prototype]]: Object {...}
  • constructor references the function itself.
  • [[Prototype]] references the prototype property the function inherited from its constructor. We sometimes call it "dunder proto."

3. The prototype property is mutable

Although an object is prototype's default value, you can change it to any data type or add extra items.

Here's an example:

// Define a function:
function companyProfile() {}

// Check the companyProfile's prototype property's content:
companyProfile.prototype;

// The invocation above will return:
// {...}:
// constructor: function companyProfile()
// [[Prototype]]: Object {...}

// Add a new property to the companyProfile's prototype property:
companyProfile.prototype.name = "CodeSweetly";

// Check the companyProfile's prototype property's content:
companyProfile.prototype;

// The invocation above will return:
// {...}:
// constructor: function companyProfile()
// name: "CodeSweetly"
// [[Prototype]]: Object {...}

// Change the constructor property's value:
companyProfile.prototype.constructor = "You were a function but now a string!";

// Check the companyProfile's prototype property's content:
companyProfile.prototype;

// The invocation above will return:
// {...}:
// constructor: "You were a function but now a string!"
// name: "CodeSweetly"
// [[Prototype]]: Object {...}

// Replace the entire content of the companyProfile's prototype property:
companyProfile.prototype = {
totalReplacement: "This is a complete replacement!!!",
};

// Check the companyProfile's prototype property's content:
companyProfile.prototype;

// The invocation above will return:
// {...}:
// totalReplacement: "This is a complete replacement!!!"
// [[Prototype]]: Object {...}

You can see that JavaScript gives you complete control of the prototype property. But "with great freedom comes great responsibility—Eleanor Roosevelt."

4. Modify prototype with caution!

Some alterations on the prototype property will break the inheritance chain of the function and its subsequent object instances. So, be careful while modifying it.

You should prefer adding items to prototype's default object rather than replacing it.

For instance, companyProfile.prototype = { name: "value" } will break companyProfile's prototype chain—which you should avoid.

A better alternative is to update the default object by adding items like this: companyProfile.prototype.name = "value".

5. New prototype object needs a new constructor

Suppose you choose to replace prototype's default object with a new value. In that case, remember to define a new constructor property. Otherwise, your function's prototype will have no constructor feature. And its object instances will inherit Object()'s prototype directly.

Here's an example:

// Define a function:
function Box() {}

// Create an object based on the Box() function:
const boxObject1 = new Box();

// Check if the boxObject1's dunder proto is the same as the global Object's prototype property:
Object.getPrototypeOf(boxObject1) === Object.prototype; // returns false

// Note: The invocation above returned false because boxObject1 inherited Box's prototype—not Object()'s.

// Replace the entire content of Box's prototype property:
Box.prototype = "Toys";

// Note: Replacing the default prototype alters Box's inheritance system.

// Create a new object based on the Box() function:
const boxObject2 = new Box();

// Check if the boxObject2's dunder proto is the same as the global Object's prototype property:
Object.getPrototypeOf(boxObject2) === Object.prototype; // returns true

// Note: The invocation above returned true because boxObject2 inherited Object()'s prototype directly—not Box's.

Try Editing It

boxObject2 inherited the global Object's prototype directly because we replaced Box's prototype without providing a new constructor property.

6. Avoid modifying built-in objects' prototype properties

Extending any built-in prototypes, such as the Object.prototype, is a bad coding practice because it breaks JavaScript's prototype chain.

In other words, avoid altering the prototype property of the objects you did not create.

note
  • Monkey patching is the act of extending a built-in object's prototype.
  • Although you may find monkey patching in some popular frameworks, it is best to avoid cluttering built-in objects' prototypes with additional non-standard features—except if you want to backport newer JavaScript features, like Array.forEach.
  • "Extending an object" means adding to or modifying the object's features.

7. Put static items in the prototype property

Developers typically structure a constructor function as follows:

  • Define dynamic items, like variables, in the constructor function's body.
  • Define static data, like methods, in the constructor function's prototype property.

Here's an example:

// Define a constructor with only properties:
function MyCar(whl, gBox, mirr) {
this.wheel = whl;
this.gearbox = gBox;
this.mirrors = mirr;
}

// Define MyCar's methods inside its prototype:
MyCar.prototype.showFeatures = function () {
return `My car has ${this.wheel} wheels, ${this.gearbox} gearbox, and ${this.mirrors} mirrors.`;
};

The snippet above structured the constructor function as follows:

  • MyCar's body contains items whose values users may change (dynamic values).
  • MyCar's prototype has items whose value we do not expect users to alter (static value).

Note the following:

  • A constructor function contains own and prototype items.
  • Own properties are the items in an object's body.
  • Prototype features are the items in an object's prototype property.
  • wheel, gearbox, and mirrors are the owned properties because they are not inheritable through the prototype property.
  • showFeatures is a shared feature because MyCar's object instances will inherit the method through the constructor's prototype property.
  • We used the this keyword to assign the own properties to MyCar's object instances.
  • JavaScript creates new own properties whenever you use the new keyword to construct a new object instance. In contrast, the computer shares a constructor's prototype features with all object instances. It doesn't create new prototype items.

8. Some functions do not have a default prototype property

Arrow functions, methods, and asynchronous functions do not have built-in prototype properties. Therefore, you cannot use them as constructor functions—even if you later add a prototype manually.

For instance, consider the following code:

const myArrowFunction = () => {};
const myMethod = { oluwatobi() {} };
async function myAsyncFunction() {}

myArrowFunction.prototype; // returns undefined
myMethod.oluwatobi.prototype; // returns undefined
myAsyncFunction.prototype; // returns undefined

Try Editing It

The invocations in the snippet above returned undefined because arrow functions, methods, and asynchronous functions do not have built-in prototype properties.

What Is the Default [[Prototype]] Property in JavaScript Functions?

[[Prototype]] is the prototype property a function (or object) inherits from its constructor.

note
  • The [[Prototype]] property is sometimes called the dunder proto, inherited prototype, <prototype>, or __proto__.
  • __proto__ has two underscore characters on either side of proto.

Here's an example:

// Define a function:
function companyProfile() {}

// Check the companyProfile's prototype property's content:
companyProfile.prototype;

// The invocation above will return:
// {...}:
// constructor: function companyProfile()
// [[Prototype]]: Object {...}

The snippet above returned an object that all the companyProfile's object instances will inherit.

In other words, companyProfile.prototype is equivalent to the companyProfile's object instances' dunder proto.

Here's an example:

// Define a function:
function companyProfile() {}

// Create an object based on the companyProfile function:
const bestWebsite = new companyProfile();

// Check bestWebsite's dunder proto's content:
Object.getPrototypeOf(bestWebsite);

// The invocation above will return:
// {...}:
// constructor: function companyProfile()
// [[Prototype]]: Object {...}

// Check if companyProfile's prototype is equivalent to bestWebsite's dunder proto:
companyProfile.prototype === Object.getPrototypeOf(bestWebsite);

// The invocation above will return: true

You can see that Object.getPrototypeOf(bestWebsite) returned the same value as companyProfile.prototype. The reason is that bestWebsite's dunder proto contains the prototype that the object inherited from its constructor (companyProfile).

Deprecated feature

__proto__ is now deprecated. We previously used it to check the content of an object's dunder proto.

Here's an example:

// Define a function:
function companyProfile() {}

// Create an object based on the companyProfile function above:
const bestWebsite = new companyProfile();

// Instead of Object.getPrototypeOf(bestWebsite), we previously __proto__ to check an object's dunder proto:
bestWebsite.__proto__;

// The invocation above will return:
// {...}:
// constructor: function companyProfile()
// [[Prototype]]: Object {...}

// Check if companyProfile's prototype is equivalent to bestWebsite's dunder proto:
companyProfile.prototype === bestWebsite.__proto__;

// The invocation above will return: true

// Instead of Object.getPrototypeOf(Object.getPrototypeOf(bestWebsite)), we previously used:
bestWebsite.__proto__.__proto__;

// The invocation above will return an output similar to the following:
// {constructor: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}:
// constructor: ƒ Object()
// hasOwnProperty: ƒ hasOwnProperty()
// isPrototypeOf: ƒ isPrototypeOf()
// propertyIsEnumerable: ƒ propertyIsEnumerable()
// toLocaleString: ƒ toLocaleString()
// toString: ƒ toString()
// valueOf: ƒ valueOf()

Developers typically use the term "prototype chain" to reference JavaScript's inheritance system. Let's see how it works.

How JavaScript's Inheritance System Works

Consider the constructor function below and its object instance.

// Define a constructor function:
function MyCar(whl, gBox, mirr) {
this.wheel = whl;
this.gearbox = gBox;
this.mirrors = mirr;
}

// Create an object based on MyCar:
const mySpecialCar = new MyCar(35, 1, 7);

The snippet above created mySpecialCar object from MyCar() constructor function.

Suppose you invoke a feature that isn't one of MyCar()'s own properties (for instance, mySpecialCar.valueOf()). In that case, here is what JavaScript will do:

note
  • The steps below use the [[Prototype]] syntax for simplicity and readability.
  • [[Prototype]] is equivalent to the Object.getPrototypeOf() method (or the deprecated __proto__ accessor property).

1. Check if mySpecialCar object has a valueOf() method

The computer will check for a valueOf() method in the mySpecialCar object instance. But it will find none, so it moves to the next scope to continue its quest.

2. Check if mySpecialCar's dunder proto has a valueOf() method

Since valueOf() is not in the mySpecialCar object, JavaScript will check if mySpecialCar's dunder proto has a valueOf() method as one of its properties.

In other words, the computer looks for valueOf() in mySpecialCar.[[Prototype]]. But it will find none there either, so it climbs up the ladder to the next scope.

note

mySpecialCar.[[Prototype]]'s value is equivalent to MyCar.prototype.

3. Check if mySpecialCar's dunder proto's [[Prototype]] has a valueOf() method

JavaScript will check if the dunder proto of mySpecialCar's [[Prototype]] has a valueOf() method as one of its properties.

In other words, the computer looks for valueOf() in mySpecialCar.[[Prototype]].[[Prototype]]. And it finds it there!!!

note

mySpecialCar.[[Prototype]].[[Prototype]]'s value is equivalent to Object.prototype.

Therefore, the mySpecialCar instance object will inherit the valueOf() method from Object.prototype.

As a result, the mySpecialCar.valueOf() invocation will successfully return mySpecialCar's value ({wheel: 35, gearbox: 1, mirrors: 7}).

Here's an example:

// Define a constructor function:
function MyCar(whl, gBox, mirr) {
this.wheel = whl;
this.gearbox = gBox;
this.mirrors = mirr;
}

// Create an object based on MyCar() constructor function:
const mySpecialCar = new MyCar(35, 1, 7);

// Display mySpecialCar's value:
mySpecialCar.valueOf();

// The invocation above will return:
// {wheel: 35, gearbox: 1, mirrors: 7}

Try Editing It

JavaScript's inheritance system is sometimes called "prototype chain" or "prototypal inheritance."

Prototypal inheritance refers to objects inheriting a constructor's prototype.

In other words, you can say that mySpecialCar prototypically inherits the valueOf() method from the Object() constructor's prototype property.

TLDR

The main gist of the walk-through above is that JavaScript does not limit its search for a feature to an object instance's scope only. Instead, it also checks the following environments:

  1. The object instance's dunder proto.
  2. The dunder proto of the object instance's dunder proto.
  3. And so on till the computer finds a matching feature or the search reaches the end of the prototype chain.
note

JavaScript returns undefined if it does not find the searched feature in the prototype chain.

What Scope Ends JavaScript's Prototype Chain?

The Object() constructor function's scope ends JavaScript's prototype chain.

In other words, Object() has no dunder proto. It sits at the top of the JavaScript prototype chain.

Below are examples of the prototype chain in JavaScript.

What ends an Object instance's prototype chain?

// Create an object:
const myObject = Object();

// Check myObject's prototype chain:
Object.getPrototypeOf(Object.getPrototypeOf(myObject)); // Equivalent to: myObject.__proto__.__proto__

// The invocation above will return: null

Try Editing It

The snippet above returned null because Object() is the prototype chain's final link.

  • myObject inherited Object()'s prototype (myObject.[[Prototype]]).
  • Object() inherits no constructor's prototype. So, myObject.[[Prototype]].[[Prototype]]'s value is null.

Therefore, myObject's prototype chain looks like this:

{} ---> Object.prototype ---> null

What ends an Array instance's prototype chain?

// Create an array:
const myArray = Array();

// Check myArray's prototype chain:
Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(myArray))); // Equivalent to: myArray.__proto__.__proto__.__proto__

// The invocation above will return: null

Try Editing It

The snippet above returned null because Object() is the prototype chain's final link.

  • myArray inherited Array()'s prototype (myArray.[[Prototype]]).
  • Array() inherited Object()'s prototype (myArray.[[Prototype]].[[Prototype]]).
  • Object() inherits no constructor's prototype. So, myArray.[[Prototype]].[[Prototype]].[[Prototype]]'s value is null.

Therefore, myArray's prototype chain looks like this:

[] ---> Array.prototype ---> Object.prototype ---> null

What ends a Function instance's prototype chain?

// Create a function:
const myFunction = Function();

// Check myFunction's prototype chain:
Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(myFunction))); // Equivalent to: myFunction.__proto__.__proto__.__proto__

// The invocation above will return: null

Try Editing It

The snippet above returned null because Object() is the prototype chain's final link.

  • myFunction inherited Function()'s prototype (myFunction.[[Prototype]]).
  • Function() inherited Object()'s prototype (myFunction.[[Prototype]].[[Prototype]]).
  • Object() inherits no constructor's prototype. So, myFunction.[[Prototype]].[[Prototype]].[[Prototype]]'s value is null.

Therefore, myFunction's prototype chain looks like this:

function anonymous() {} ---> Function.prototype ---> Object.prototype ---> null

What ends the wifeProfile instance's prototype chain?

// Create an object:
const myName = { name: "Oluwatobi" };

// Create another object based on myName:
const bestFriend = Object.create(myName);

// Create a third object based on bestFriend:
const wifeProfile = Object.create(bestFriend);

// Check wifeProfile's prototype chain:
Object.getPrototypeOf(
Object.getPrototypeOf(
Object.getPrototypeOf(Object.getPrototypeOf(wifeProfile))
)
); // Equivalent to: wifeProfile.__proto__.__proto__.__proto__.__proto__

// The invocation above will return: null

Try Editing It

tip

The new object the Object.create() method creates uses the method's first argument as its prototype.

The snippet above returned null because Object() is the prototype chain's final link.

  • wifeProfile inherited bestFriend as its dunder proto (wifeProfile.[[Prototype]]).
  • bestFriend inherited myName as its dunder proto (wifeProfile.[[Prototype]].[[Prototype]]).
  • myName inherited Object()'s prototype (myName.[[Prototype]].[[Prototype]].[[Prototype]]).
  • Object() inherits no constructor's prototype. So, myFunction.[[Prototype]].[[Prototype]].[[Prototype]].[[Prototype]]'s value is null.

Therefore, wifeProfile's prototype chain looks like this:

{} ---> {} ---> { name: "Oluwatobi" } ---> Object.prototype ---> null

The four examples above show that JavaScript's inheritance chain ends at the Object() constructor function's scope.

Let's use a diagram to illustrate the prototype chain.

The JavaScript prototype chain diagram

The code below describes mySpecialCar's prototype chain.

// Define a constructor function:
function MyCar(whl) {
this.wheel = whl;
}

// Create an object based on the MyCar constructor function:
const mySpecialCar = new MyCar(35);

// Check mySpecialCar's prototype chain:
Object.getPrototypeOf(
Object.getPrototypeOf(Object.getPrototypeOf(mySpecialCar))
); // Equivalent to: mySpecialCar.__proto__.__proto__.__proto__

// The invocation above will return: null

Try Editing It

The snippet above returned null because Object() is the prototype chain's final link.

  • mySpecialCar inherited MyCar's prototype (mySpecialCar.[[Prototype]]).
  • MyCar inherited Object()'s prototype (mySpecialCar.[[Prototype]].[[Prototype]]).
  • Object() inherits no constructor's prototype. So, mySpecialCar.[[Prototype]].[[Prototype]].[[Prototype]]'s value is null.

Therefore, mySpecialCar's prototype chain looks like this:

{ wheel: 35 } ---> MyCar.prototype ---> Object.prototype ---> null

Below is the diagram illustrating mySpecialCar's prototype chain.

The JavaScript prototype chain
diagram

mySpecialCar has the prototypes of only MyCar and Object in its prototype chain.

The diagram above shows that the Object() constructor function is the prototype chain's last link—it inherits nothing (null) from any other constructor.

Although we used a constructor function in the illustration above, the diagram works for all JavaScript objects—regardless of how you've created them.

Suppose you wish to set an object's dunder proto during its creation rather than alter its prototype chain afterward. How can you do this? Let's find out.

How to Specify an Object's Dunder Proto at Creation Time

There are two main ways to specify an object's dunder proto ([[Prototype]]) at creation time (when you are creating the object).

  1. Use the Object.create() method.
  2. Use __proto__ as an object literal's own property.
info

To use __proto__ as an object literal's own property is acceptable, optimized, and not deprecated. We will discuss this in detail later in this article.

Let's discuss the two techniques now.

How to use the Object.create() method to specify an object's dunder proto

The Object.create() method does the following:

  1. It creates a new object.
  2. It makes its first argument the newly created object's dunder proto.

Therefore, you can use Object.create() to specify an object's dunder proto like so:

// Create an object:
const myName = { name: "Oluwatobi" };

// Create another object based on myName:
const bestFriend = Object.create(myName);

// Check bestFriend's content:
bestFriend;

// The invocation above will return: {}

// Check bestFriend's dunder proto:
Object.getPrototypeOf(bestFriend); // Equivalent to: bestFriend.__proto__

// The invocation above will return: { name: "Oluwatobi" }

Try Editing It

The snippet above used Object.create() to create a new object and assign myName as the newly created object's dunder proto.

Let's see the second way to specify an object's dunder proto at creation time.

How to use __proto__ to specify an object's dunder proto

Instead of the Object.create() method, you can define a __proto__ property directly in an object literal like so:

// Create an object:
const myName = { name: "Oluwatobi" };

// Create another object based on myName:
const bestFriend = { __proto__: myName };

// Check bestFriend's content:
bestFriend;

// The invocation above will return: {}

// Check bestFriend's prototype:
Object.getPrototypeOf(bestFriend); // Equivalent to: bestFriend.__proto__

// The invocation above will return: { name: "Oluwatobi" }

Try Editing It

The snippet above used __proto__ as an own property to assign myName as the newly created object's dunder prototype.

note

JavaScript allows only one __proto__ property in an object literal. Otherwise, it will throw a SyntaxError.

__proto__ Own Property vs. __proto__ Prototype Accessor: What's the Difference?

To use __proto__ as an own property and to use it as a prototype accessor works in different ways. The sections below discuss the main distinctions between them.

What is a __proto__ own property?

A __proto__ own property allows you to define an object literal's dunder proto at creation time.

Here's an example:

const myName = { name: "Oluwatobi" };
const bestFriend = { __proto__: myName };

The snippet above used __proto__ as the object literal ({})'s own property.

In this instance, __proto__ is standardized, optimized, and not deprecated. You can freely use it in your codebase. Its performance may even be better than the Object.create() method.

note
  • The __proto__: value syntax does not create a property named __proto__. We use it to define the value of an object literal's dunder proto.
  • __proto__'s value must be an object or null. Otherwise, JavaScript will not change the object literal's dunder proto.

What is a __proto__ prototype accessor?

A __proto__ accessor allows you to access an object's inherited prototype.

Here's an example:

const bestFriend = {};
bestFriend.__proto__;

The snippet above used __proto__ to access the prototype bestFriend inherited from its constructor.

In this instance, __proto__ is non-standard, deprecated, and no longer recommended. A better alternative is to use Object.getPrototypeOf() like so:

const bestFriend = {};
Object.getPrototypeOf(bestFriend);

Suppose you wish to check whether a specific prototype exists in an object's prototype chain. How can you do this? Let's find out.

How to Confirm If a Specific prototype Exists in an Object's Prototype Chain

Use the isPrototypeOf() method to check if a specific prototype exists in an object's prototype chain.

Example 1: How to check if Object.prototype is in MyCar's prototype chain

// Define a constructor function:
function MyCar() {}

// Check if Object.prototype exists in MyCar's prototype chain:
Object.prototype.isPrototypeOf(MyCar);

// The invocation above will return: true

Try Editing It

The snippet above returned true because MyCar inherited the global Object()'s prototype from Function.prototype. Therefore, Object's prototype is one of MyCar's dunder protos.

In other words,

Object.prototype === Object.getPrototypeOf(Object.getPrototypeOf(MyCar));
// The code above is equivalent to the deprecated __proto__ syntax:
// Object.prototype === MyCar.__proto__.__proto__

Example 2: How to check if two given prototypes exist in mySpecialCar's prototype chain

// Define a constructor function:
function MyCar() {}

// Create an object based on the MyCar constructor function:
const mySpecialCar = new MyCar();

// Check if MyCar.prototype exists in mySpecialCar's prototype chain:
MyCar.prototype.isPrototypeOf(mySpecialCar);

// The invocation above will return: true

// Check if Object.prototype exists in mySpecialCar's prototype chain:
Object.prototype.isPrototypeOf(mySpecialCar);

// The invocation above will return: true

Try Editing It

The snippet above returned true because mySpecialCar inherited MyCar's prototype. Therefore, MyCar.prototype and Object.prototype are part of MyCar's dunder protos.

Example 3: How to check if MyCar.prototype is in mySpecialCar's prototype chain

// Define a constructor function:
function MyCar() {}

// Define another constructor function:
function WifeCar() {}

// Define a third constructor function:
function ChildCar() {}

// Change the WifeCar's dunder proto to MyCar's prototype:
WifeCar.prototype = {
constructor: WifeCar, // Added to retain WifeCar's constructor.
__proto__: MyCar.prototype,
};

// Change the ChildCar's dunder proto to WifeCar's prototype:
ChildCar.prototype = {
constructor: ChildCar, // Added to retain ChildCar's constructor.
__proto__: WifeCar.prototype,
};

// Create an object based on the ChildCar constructor function:
const mySpecialCar = new ChildCar();

// Check if MyCar.prototype exists in mySpecialCar's prototype chain:
MyCar.prototype.isPrototypeOf(mySpecialCar);

// The invocation above will return: true

Try Editing It

The snippet above returned true because mySpecialCar inherited MyCar's prototype from WifeCar.prototype. Therefore, MyCar's prototype is one of mySpecialCar's dunder protos.

Now that you know what prototype is, we can discuss why it is an essential JavaScript feature.

Why Is Prototype Essential in JavaScript?

Prototype helps you optimize your code by allowing objects to inherit one another's features.

In other words, a JavaScript prototype is the chain linking one object to another object.

For instance, suppose you want users to use a getInfo() method to access some books' data. In that case, you can add the method as each book's own property like so:

// Define a book object:
const book1 = {
name: "React Explained Clearly",
pages: 269,
formats: ["kindle", "paperback", "hardcover"],
getInfo(key) {
return this[key];
},
};

// Define another book object:
const book2 = {
name: "Creating NPM Package",
pages: 174,
formats: ["kindle", "paperback"],
getInfo(key) {
return this[key];
},
};

// Define a third book object:
const book3 = {
name: "The CSS Grid Guidebook",
pages: 123,
formats: ["kindle", "paperback"],
getInfo(key) {
return this[key];
},
};

// Get the second book's total pages:
book2.getInfo("pages");

// The invocation above will return: 174

Try Editing It

The snippet above works—but it is subpar. Repeating the same method in each object is redundant and unnecessary. A better way to lower memory usage is to set getInfo() as each book's dunder proto on creation.

Here's an example:

// Define a getInfo method:
const getInfoMethod = {
getInfo(key) {
return this[key];
},
};

// Define a book object:
const book1 = {
name: "React Explained Clearly",
pages: 269,
formats: ["kindle", "paperback", "hardcover"],
__proto__: getInfoMethod,
};

// Define another book object:
const book2 = {
name: "Creating NPM Package",
pages: 174,
formats: ["kindle", "paperback"],
__proto__: getInfoMethod,
};

// Define a third book object:
const book3 = {
name: "The CSS Grid Guidebook",
pages: 123,
formats: ["kindle", "paperback"],
__proto__: getInfoMethod,
};

// Get the second book's total pages:
book2.getInfo("pages");

// The invocation above will return: 174

Try Editing It

You can see that we now have only one getInfo() method rather than three for the three books.

Although the code above is more performant than using the getInfo() method as each book's own feature, you can better optimize memory usage by using a constructor function's prototype property to predefine each book's dunder proto.

Here's an example:

// Define a constructor function:
function Book(name, pages, formats) {
this.name = name;
this.pages = pages;
this.formats = formats;
}

// Add the getInfo method to Book's prototype property:
Book.prototype.getInfo = function (key) {
return this[key];
};

// Define a book object:
const book1 = new Book("React Explained Clearly", 269, [
"kindle",
"paperback",
"hardcover",
]);

// Define another book object:
const book2 = new Book("Creating NPM Package", 174, ["kindle", "paperback"]);

// Define a third book object:
const book3 = new Book("The CSS Grid Guidebook", 123, ["kindle", "paperback"]);

// Get the second book's total pages:
book2.getInfo("pages");

// The invocation above will return: 174

Try Editing It

The snippet above created each book instance from the Book() constructor function, which has a getInfo() method predefined in its prototype.

Therefore, every new book object you create from the Book() constructor will inherit the getInfo() method automatically, which reduces the memory required to create new books.

Overview

This article discussed the six default function properties. We also used examples to discuss how JavaScript's inheritance system works.

Your support matters: Buy me a coffee to support CodeSweetly's mission of simplifying coding concepts.

Join CodeSweetly Newsletter