¿Hay alguna diferencia entre extender Object vs not extending en absoluto en javascript?

Descubrí que puedo extender Object así:

class MyObject extends Object {} 

¿Hay alguna diferencia con esto y no se extiende en absoluto, así:

 class MyObject {} 

La razón por la que pregunto esto es porque tengo la siguiente mezcla:

 const MapMixin = (Base = Object) => class extends Base { static from(array) { return new this(Object.assign(...array.map(([key, value]) => ({[key]: value})))); } map(...args) { return this.constructor.from(this.entries().map(...args)); } entries() { return Object.entries(this); } }; 

Esta mixin podría usarse así:

 class MyObject extends MapMixin(MyBaseClass) {} 

Pero si no hay una class base, ahora he especificado que amplíe Object como valor pnetworkingeterminado:

 class MyObject extends MapMixin() {} 

Entonces me pregunto, si esto funciona prácticamente igual que no extender nada en absoluto.

No sé si está claro de las otras respuestas aquí, pero la diferencia está en la inheritance estática .

Antes de la palabra key class , la inheritance en JavaScript se ha centrado mucho en la inheritance de instancias. Nadie (que yo haya visto) se preocupó por tener una class / constructor henetworkingando miembros estáticos de la superclass / constructor. Sin mencionar que la única forma de hacerlo fue a través de la propiedad __proto__ no estándar.

Entonces, cuando vemos una class que amplía otra class hoy, pensamos en cómo funciona la inheritance entre las instancias de esa class. Para las instancias, extender Object , o nada en absoluto, es lo mismo porque las instancias henetworkingarán inherentemente de Object como base.

 class A {} class B extends Object {} let a = new A() let b = new B() // a.__proto__.__proto__ === b.__proto__.__proto__ === Object.prototype 

Pero puede no estar claro, o bien entendido, que la palabra key extends está haciendo algo más que solo configurar inheritance para las instancias. También configura la inheritance entre los constructores de la class. Entonces para B anterior, el uso de extends también significa que Object.setPrototypeOf(B, Object) se llama en el background para B. Entonces, por ejemplo:

 class A {} // A constructor inherits nothing (is a basic Function type) class B extends Object {} // B inherits from Object // A.setPrototypeOf === undefined // B.setPrototypeOf === Object.setPrototypeOf 

B , extendiendo Object , henetworkinga todos los methods estáticos de Object , mientras que A no extiende nada, no lo hace.

La diferencia está entre B.prototype (o B.prototype.__proto__ ) – de qué henetworkingan las instancias, y B.__proto__ – de qué henetworkinga el constructor de la class. Extender Object o no no afecta al prototype ni a qué henetworkingan las instancias, pero sí a la class __proto__ , o inheritance estática.

Hay una sutil diferencia.

Si declaras las classs A, B y creas instancias como esta:

 class A {} class B extends Object {} let a = new A() let b = new B() 

A es una class base , y B es una class derivada .

Como resultado, a se asigna directamente desde A pero b se asigna desde Object .
Para que pueda encontrar sus prototypes:

 console.log(A.__proto__) // [Function] (Function.prototype) console.log(B.__proto__) // [Function: Object] (Object) 

a través de http://2ality.com/2015/02/es6-classes-final.html#the-extends-clause .

Como dijo Shu Ding , la cadena de prototypes difiere

Para ser más explícito:

 const getNProtos = (n, { __proto__:p }={}, protos=[]) => n && p ? getNProtos(n-1, p, [ ...protos, p ]) : [ ...protos, p ] [ class extends Object{}, class extends (class {}){}, class {} ].map(obj => getNProtos(3, obj) .forEach(x => x.forEach(y => console.log(y)) || console.log('\n')) ) ƒ Object() { [native code] } ƒ () { [native code] } {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …} null class {} ƒ () { [native code] } {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …} null ƒ () { [native code] } {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …} null 

Las cadenas de prototypes son casi idénticas, y la class derivada simplemente tiene una extra (el constructor de Objetos) encima de la cadena. La extensión con Object es similar a la extensión con una class {} simple class {} , excepto, por supuesto, que Object tiene sus propios methods disponibles.