This is because, in fact, methods such as sort
do not belong to the builder Array
, but yes to the Array.prototype
.
Note, in the exit code you ran, that the Array
has a property called prototype
. This is where are all the methods and properties that can be accessed in any instance of Array
.
So, to list all the methods of instances of a Array
, do:
console.log(Object.getOwnPropertyNames(Array.prototype));
In Javascript, when you instantiate an object from a constructor, the object <constructor>.prototype
will be associated with the prototype of the built object. This is explained in more detail in How the Javascript prototype chain works?. The question of nomenclature is explained in more detail here.
Think of the properties of Array
as "static methods" and in the properties of Array.prototype
as "instance methods".
Note that the syntax of array literal is basically syntactic sugar for new Array()
. So the two ways to create a array below are equivalent:
const arr1 = new Array();
const arr2 = [];
Note that you cannot use the function Object.getOwnPropertyNames
directly in an instance to try to access its "inherited" methods, since, as the function name says, only the "Own properties", that is, the properties defined in the object itself will be returned. As properties like sort
and forEach
were not defined directly in each instance, but in your prototype, you will not have access to them.
You can use the function Reflect.getPrototypeOf
to access the prototype of any object, which, theoretically, cannot be accessed "directly":
console.log(
// Retorna as propriedades do protótipo de `[]` (uma instância de `Array`)
Object.getOwnPropertyNames(
// Acessa o protótipo do 1º argumento. No caso, `[]`.
Reflect.getPrototypeOf([])
)
);
I used the term "theoretically" above because, by specification, the prototype of an object is an "internal property of language". However, there are ways to access it, such as property __proto__
and the functions Object.getPrototypeOf
and Reflect.getPrototypeOf
.
When you give a console.dir
in some object (such as an instance of Array
— []
), the property __proto__
that appears there is a reference to the prototype of the object. It is this prototype (which is not "accessible" directly, as we have seen above) which contains the methods (such as sort
or forEach
) that you use.
It’s a bit confusing. Be sure to understand what is prototype in Javascript (something essential to understand this answer). This another answer is also excellent. Also, be sure to know how to nomenclature works not to write wrong (Array.prototype.forEach
is different from Array.forEach
).
If you really want to list all properties (including nonenumerable, symbols and "inherited" via prototypical inheritance), you can do your own function dir
. Thus:
function dir(obj) {
const allKeys = new Set();
let currProto = Object(obj);
while (currProto) {
for (const key of Reflect.ownKeys(currProto)) {
allKeys.add(key);
}
currProto = Reflect.getPrototypeOf(currProto);
}
// Retorna em formato de array por conveniência.
return [...allKeys];
}
The code basically traverses the entire chain of prototypes of the given value by inserting into the set all the properties he finds. I used the Set
because it avoids duplicated elements (which may occur).
If there are duplicated properties, the "next" one will be returned - this behavior is due to the prototypical Javascript model. Learn more about the Reflect.ownKeys
.
Example of use:
function dir(obj) {
const allKeys = new Set();
let currProto = Object(obj);
while (currProto) {
for (const key of Reflect.ownKeys(currProto)) {
allKeys.add(key);
}
currProto = Reflect.getPrototypeOf(currProto);
}
return [...allKeys];
}
const myArr = [1, 2, 3];
const allKeys = dir(myArr);
console.log(allKeys.includes('0')); //=> true; índice 0 (é uma propriedade, já que arrays nada mais são que objetos)
console.log(allKeys.includes('map')); //=> true; herdada via herança prototípica
console.log(allKeys.includes('from')); //=> false; é método "estático" de array. Logo, não existe na instância
console.log(allKeys);
The null
that appeared on the last console.log
of the above example are the properties with symbolic key (type symbol
). The console of snippet Stack Overflow does not know how to display symbols correctly, which justifies the impression of null
.