The "prototype" property is commonly used by the core of JavaScript. It is used by all the built-in constructor functions.
Let’s start at the details.
Object.prototype
Imagine you output an object that is empty:

Probably, you wonder where the code creating the string "[object Object]" is. It is the built-in toString method. But, in fact, the obj is empty.
Note that short notation obj = {} is equal to obj = new Object(), where Object is a built-in object constructor function along with its prototype referencing an immense object with toString or other methods.

Whenever, a new Object() is invoked, its [[Prototype]] is set to Object.prototype:

As you can see, when you call obj.toString(), the method is taken from Object.prototype.
You have the option of checking it, acting like this:

Please, take into account that the prototype doesn’t exist any more in the chain above Object.prototype.
It looks like this:

Other Built-in Prototypes
Array, Date, Function, and other built-in objects keep methods in prototypes, as well.
For example, if you create an array ['a', 'b', 'c'], the default new Array() constructor is implemented internally. Hence, Array.prototype grows into its prototype providing methods. It is quite efficient for memory. There is Object.prototype on the top of overall built-in prototypes. The popular opinion that “ everything inherits from objects” comes from here.
For the manual check of the prototypes, you should act like this:

Part of the methods in prototype can possibly overlap. For example, the Array.prototype has its toString, which is targeted at listing comma-delimited elements, as follows:

Also, the Array.prototype obtains toString, but Array.prototype is nearer in the chain. Hence, the array option is used.

Chrome developer console also shows inheritance.
Other built-in objects operate similarly. The functions, as well, are objects of a built-in Function constructor. Their methods (call , apply, and more) are taken from Function.prototype . Likewise, the functions have toString .

Primitives
Now, let’s see what happens with strings, booleans, and numbers. As you already know, they are not objects. But when you try to access their properties, temporary wrapper objects are generated using built-in constructors, such as String, Number, and Boolean. After providing methods, they disappear.
They are created out of your sight, and most of the engines optimize them out. Their methods, as well, reside in prototypes, available as Number.prototype, String.prototype, and Boolean.prototype.
Special values, such as null and undefined , don’t have wrappers. Therefore, methods and properties are not available to them. Neither they have matching prototypes.
Modifying Native Prototypes
It is possible to modify native prototypes. Adding a method to String.prototype makes it available to all the strings.
For instance:

It is essential to know that prototypes are global. Hence, there is a high possibility of getting a conflict. For example, if two libraries add a String.prototype.welcome method, one will overwrite the method of the other. So, it is not considered a good idea to modify a native prototype.
In nowadays programming, modifying native prototypes can be approved in one case. It’s polyfilling. Polyfilling is used to make a substitute for a method that exists in the JavaScript specification. But it’s not yet supported by a specific JavaScript engine.
It is necessary to implement it manually, populating the built-in prototype with it.
Here is an example:

Borrowing from Prototypes
We have already spoken about method borrowing in the chapter Decorators and Forwarding, Call/Apply.
It’s when one takes a method from an object and copies it into another. Often some of the native prototypes’ methods are borrowed. For example, if you are creating an array-like object, you may need to copy several Array methods to it:

Another way of inheriting is to set obj.__proto__ to Array.prototype . Thus, all array methods can be automatically available in obj . But that is impossible when obj inherits from another one. Note that you can inherit from one object only once.
Borrowing methods allow the mixing of functionalities from different objects.