Прежде всего, помните, что JavaScript - это в первую очередь прототипный язык , а не язык на основе классов 1 . Foo
это не класс, это функция, которая является объектом. Вы можете создать экземпляр объекта из этой функции, используя new
ключевое слово, которое позволит вам создать нечто похожее на класс на стандартном языке ООП.
Я бы посоветовал игнорировать __proto__
большую часть времени, потому что он плохо поддерживает кросс-браузер, и вместо этого сосредоточиться на изучении того, как prototype
работает
Если у вас есть экземпляр объекта, созданный из функции 2, и вы обращаетесь к одному из его членов (методы, атрибуты, свойства, константы и т. Д.) Любым способом, доступ будет течь вниз по иерархии прототипа, пока он (а) не найдет участник, или (b) не находит другого прототипа.
Иерархия начинается с объекта, который был вызван, а затем ищет его объект-прототип. Если объект-прототип имеет прототип, он повторяется, если прототип не существует, undefined
возвращается.
Например:
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
Мне кажется, что вы, по крайней мере, в некоторой степени уже поняли эти "основные" части, но я должен сделать их явными, чтобы быть уверенным
В JavaScript все является объектом 3 .
все является объектом.
function Foo(){}
не просто определяет новую функцию, она определяет новый объект функции, к которому можно получить доступ, используя Foo
.
Вот почему вы можете получить доступ Foo
к прототипу с помощью Foo.prototype
.
То , что вы также можете сделать , это установить дополнительные функции по Foo
:
Foo.talk = function () {
alert('hello world!');
};
Эта новая функция может быть доступна с помощью:
Foo.talk();
Я надеюсь, что к настоящему времени вы заметили сходство функций в функциональном объекте и статическом методе.
Представьте, f = new Foo();
что вы создаете экземпляр класса, Foo.prototype.bar = function(){...}
определяете общий метод для класса и Foo.baz = function(){...}
определяете открытый статический метод для класса.
ECMAScript 2015 представил множество синтаксических символов для этих видов объявлений, чтобы их было проще реализовать, а также было легче читать. Поэтому предыдущий пример можно записать так:
class Foo {
bar() {...}
static baz() {...}
}
который позволяет bar
называться:
const f = new Foo()
f.bar()
и baz
называться как:
Foo.baz()
1: class
было «Future Reserved Word» в спецификации ECMAScript 5 , но ES6 вводит возможность определять классы, используя class
ключевое слово.
2: по сути, экземпляр класса, созданный конструктором, но есть много нюансов, которые я не хочу вводить в заблуждение
3: примитивные значения, которые включают undefined
, null
логические, числа и строки, технически не являются объектами, потому что они являются низкоуровневыми реализациями языка. Булевы числа, числа и строки по-прежнему взаимодействуют с цепочкой прототипов, как если бы они были объектами, поэтому для целей этого ответа легче считать их «объектами», даже если они не совсем.
Foo.talk = function ...