(или одолжить степлер)
Привет! Я Дауд, разработчик JavaScript с большим опытом работы в сфере образования. Я попытаюсь объяснить некоторые концепции JS для начинающих и среднего уровня с помощью аналогий, примеров кода и *zero* foo и bar (обещаю!) Не стесняйтесь обращаться ко мне, если у вас есть какие-либо вопросы о том, что я написал.
Предпосылки:
Просто немного синтаксиса ES6, например оператор распространения и классы. Это поможет понять «область охвата», «контекст» и
this
, но не обязательно для понимания этого поста и начала использования прототипов.
Добро пожаловать
После нескольких энергичных раундов интервью вы сделали это! Вы новый сотрудник Компании, и пришло время получить приветственный набор. Вещи немного бессистемны, кажется, никто официально не принял вас на борт, но рядом есть услужливый коллега, чтобы привести в порядок ваши приветственные документы и передать вам и степлер (все для себя!). Внезапно улыбнувшись, она строго смотрит тебе в глаза и говорит:
«Этот степлер для вас. Это только для тебя».
Почти так же быстро все возвращается к веселым шуткам, и через несколько мгновений пришло время найти свой стол. Понятно, что, держа в руках набор из трех отдельных страниц формата А4 и степлер, первое, что вы делаете, это скрепляете их вместе.
Большой! Ваш новый блестящий степлер работает именно так, как вы и ожидали.
Через несколько часов после того, как вы устроились за вашим компьютером, потрепанный, небритый парень представляется как «Джон». Вы чувствуете, что он был здесь в течение очень долгого времени. Джон, похоже, сам держит в руках пачку отдельных документов:
«Это степлер?» — спрашивает он. «Когда я присоединился, они не раздавали их. Могу ли я это одолжить?"
Вы вспоминаете тот странный момент с другим коллегой… «Нет, боюсь, что нет», — застенчиво отвечаете вы. «Этот степлер мой, если он вам нужен, боюсь, вам нужно увидеть того же человека, которого видела я».
Джон выглядит менее чем впечатленным; бросая на вас последний взгляд, который, кажется, кричит: «Вы правда собираетесь заставить меня пройти по коридору за степлером?», он неторопливо направляется к офису вашего услужливого коллеги.
Теперь у Джона есть собственная функция
staple()
. Несмотря на то, что функцииstaple()
наnewEmployee
иjon
идентичны, в памяти компьютера они существуют дважды.
Сокращение
«Мы потратили сколько на степлеры?!» Босс стоит над своим столом, просматривая последний отчет из бюджетного отдела, думая о своей 6-летней дочери и ее постоянных приставаниях к бассейну. Он смотрит на свой стол и на неиспользованный степлер Swingline, который лежит там годами. «Почему у каждого есть собственныйстеплер? Они все могут просто попросить использовать мою».
Начальник тут же звонит в HR: «Отныне я хочу попробовать давать новобранцам их собственные документы, но перестаньте давать им степлеры! Они могут одолжить мой степлер, если он им понадобится».
Ваш услужливый коллега хлопает вас по плечу. «Извините, я только что разговаривал с HR, вы должны официально пройти регистрацию через них. Кое-что о новой политике. О, и мне нужен твой степлер обратно.
Сейчас есть только один
staple()
: онtheBoss
. Помните, чтоtheBoss
— это просто переменная, которую мы используем для ссылки наEmployee.prototype
; функция существует какEmployee.prototype.staple()
.
Вызов конструктора(
new Employee
) заполняет новый объект с помощью словаthis
, вызывая функцию из внутри него. Таким образом,this
— это человек, которому «помогают», то естьthis
становитсяjon
, когда звонятjon.staple()
, иnewEmployee
, когда звонятnewEmployee.staple()
. Для простотыthis
используется только тогда, когда вы собираетесь использовать прототипы, так как код будет жить в функциях «где-то еще» вверх по цепочке прототипов и должен иметь слово для ссылки на место, где он вызывается.
Последнее слово: стрелочные функции не имеют «контекста», а это означает, что
this
вернется к контексту предыдущей области. Иногда это чрезвычайно полезно, но это «Основы наследования», поэтому я не буду углубляться; просто знайте, чтоthis
будет ссылаться на объект, в котором вызывается функция, только если он написан старым добрымfunction ()
.
Вы возвращаете степлер боссу с вежливым, но довольно робким «спасибо». Он сияет; он может видеть, как маленькая Эбигейл мгновенно надевает нарукавные повязки. «Да, это прекрасно», — думает он. «Давайте сделаем эту официальную процедуру».
Далее следует «синтаксический сахар», означающий более чистый и простой способ написания точно такой же функциональности. Стоит повторить:
class
в JavaScript, в отличие от объектно-ориентированных языков, просто вызывается функция-конструктор и помещаются методы в общий прототип (как показано выше).
Менеджер среднего звена заметил ваш свежий энтузиазм и знает, что вы новичок; она хочет, чтобы ты был в их команде. Бросившись к вам, довольно восторженная дама пожимает вам руку и представляется с натянутой улыбкой. «Нам нужны такие люди, как вы, в финансовом отделе, я думаю, вы обнаружите, что у нас репутация «любителей веселья» в компании!» Она все еще жмет тебе руку. Из-за неловкости вы ловите себя на том, что отвечаете: «Конечно, я заскочу».
"Большой! Мы постоянно приглашаем членов нашей команды на эксклюзивные встречи и мероприятия. На самом деле, у нас есть один на подходе!»
Она протягивает вам яркий флаер, украшенный статуэтками тики. «Я знаю, о чем вы думаете, — продолжает она, — больше бумаги. Но помните, вы по-прежнему получаете все основные привилегии работы в компании. Я слышал, что у Босса есть красивый степлер».
Джон мельком видит ваше приглашение. «Подождите… вы присоединились к Финансам? Они что-то празднуют? Могу ли я прийти?"
jon.getInvite(); // 'jon.getInvite() is not a function'
Извини, Джон, тебе
Employee
, но неTeamMember
. Джону помогают убрать документы и получить доступ кstapler()
, но это все! Вы обапотомкиEmployee.prototype
, но только вытакже являетесь потомкомTeamMember.prototype
.
Джон возвращается к своему столу с угрюмым видом. Вы задаетесь вопросом, есть ли у вашего соседа по комнате рубашка с пальмами, которую вы можете одолжить.
Краткое примечание
«…Но почему я не могу просто раздать всем чертов степлер?!»
Некоторые люди будут порицать ООП в JavaScript именно потому, что class
— это просто функция-конструктор и некоторые методы его прототипа (не настоящий чертеж, который может быть в других языках), другие потому, что this
сразу означает, что контекст должен поддерживаться, третьи потому что им больше подходит функциональное программирование и примеси (когда будете готовы, у меня есть статья на эту тему!). Однако если у вас есть 50 методов, к которым необходимо получить доступ для 1000 объектов, разница между 50 и 50 000 функций в памяти может повлиять на производительность. В любом случае, вы, скорее всего, увидите prototype
и/или class
в дикой природе.
В конце концов, некоторые из них вы уже использовали…
const numArray = new Array(4, 2, 1, 3);
numArray.length; // 4
numArray.sort(); // [1, 2, 3, 4]
Теперь вы знаете, почему MDN называет его Array.prototype.sort()!