En primer lugar, recuerde que JavaScript es principalmente un lenguaje prototípico , en lugar de un lenguaje basado en clases 1 . Foo
no es una clase, es una función, que es un objeto. Puede crear una instancia de un objeto de esa función utilizando la new
palabra clave que le permitirá crear algo similar a una clase en un lenguaje estándar de OOP.
Sugeriría ignorar la __proto__
mayor parte del tiempo porque tiene poca compatibilidad entre navegadores y, en su lugar, centrarse en aprender cómo prototype
funciona.
Si tiene una instancia de un objeto creado a partir de una función 2 y accede a uno de sus miembros (métodos, atributos, propiedades, constantes, etc.) de alguna manera, el acceso fluirá por la jerarquía del prototipo hasta que (a) encuentre el miembro, o (b) no encuentra otro prototipo.
La jerarquía comienza en el objeto que se llamó y luego busca su objeto prototipo. Si el objeto prototipo tiene un prototipo, se repite, si no existe ningún prototipo, undefined
se devuelve.
Por ejemplo:
foo = {bar: 'baz'};
console.log(foo.bar); // logs "baz"
foo = {};
console.log(foo.bar); // logs undefined
function Foo(){}
Foo.prototype = {bar: 'baz'};
f = new Foo();
console.log(f.bar);
// logs "baz" because the object f doesn't have an attribute "bar"
// so it checks the prototype
f.bar = 'buzz';
console.log( f.bar ); // logs "buzz" because f has an attribute "bar" set
Me parece que ya has entendido al menos estas partes "básicas", pero necesito hacerlas explícitas solo para estar seguro.
En JavaScript, todo es un objeto 3 .
Todo es un objeto.
function Foo(){}
no solo define una nueva función, sino que define un nuevo objeto de función al que se puede acceder utilizando Foo
.
Es por eso que puede acceder Foo
al prototipo con Foo.prototype
.
Lo que también puede hacer es establecer más funciones en Foo
:
Foo.talk = function () {
alert('hello world!');
};
Se puede acceder a esta nueva función usando:
Foo.talk();
Espero que ahora esté notando una similitud entre las funciones de un objeto de función y un método estático.
Piense f = new Foo();
como crear una instancia de clase, Foo.prototype.bar = function(){...}
como definir un método compartido para la clase y Foo.baz = function(){...}
como definir un método público estático para la clase.
ECMAScript 2015 introdujo una variedad de azúcar sintáctica para este tipo de declaraciones para hacerlas más simples de implementar y al mismo tiempo más fáciles de leer. Por lo tanto, el ejemplo anterior se puede escribir como:
class Foo {
bar() {...}
static baz() {...}
}
que permite bar
ser llamado como:
const f = new Foo()
f.bar()
y baz
ser llamado como:
Foo.baz()
1: class
era una "Palabra reservada para el futuro" en la especificación ECMAScript 5 , pero ES6 introduce la capacidad de definir clases usando la class
palabra clave.
2: esencialmente una instancia de clase creada por un constructor, pero hay muchas diferencias matizadas que no quiero engañarlo
3: valores primitivos -que incluyen undefined
, null
, booleanos, números y cadenas de HAYA objetos técnicamente porque son implementaciones de lenguajes de bajo nivel. Los booleanos, los números y las cadenas aún interactúan con la cadena del prototipo como si fueran objetos, por lo que a los efectos de esta respuesta, es más fácil considerarlos "objetos" aunque no lo sean del todo.
Foo.talk = function ...