Урок 3. JavaScript. Что такое замыкания. Как они работают (+ примеры)
Vložit
- čas přidán 6. 06. 2019
- Получить профессию Frontend разработчика -
bit.ly/3wwxsHf
Подробнее узнать об обучении в Result School -
bit.ly/3Ooe2IU
Бесплатный курс HTML & CSS - bit.ly/430vsTK
Сделать 5 проектов на JavaScript - bit.ly/3SXpbUn
Я в соц сетях:
Telegram: t.me/js_by_vladilen
VK: vladilen.minin
Instagram: / vladilen.minin
Мои паблики по JavaScript:
Telegram: t.me/result_school_it
VK: result.school
Instagram: / result.scho. .
JavaScript cообщества:
Discord: / discord
Telegram: t.me/js_by_vladilen_chat
Roadmap по каналу:
vladilen.notion.site/Roadmap-...
Урок 3. JavaScript. Что такое замыкания. Как они работают
В видео я расскажу, как работаю замыкания.
Вы увидите 2 примера того, как их применять в Javascript
В конце ролика будет небольшая практика на замыкания и контекст
Сложный JavaScript простым языком:
• Урок 1. JavaScript. Чт...
Смогли сами реализовать bind? Как вам идея с практикой в конце?)
Если уж и писать свой байнд, то и эплай тогда тоже надо было свой )
@@NVsquare Без него никак)
Отличный урок! А можно же в возвращаемой функции не использовать Rest, а в apply() сразу передавать arguments?
@@andreyopanasenko8771 Лучше Array.from(arguments)
Спасибо за урок!
У меня не получилось передать дополнительные параметры в функцию bind, которые передаются массивом args. В console.log выводится undefined вместо передаваемого параметра. Получается примерно такой вывод "Person: Михаил, 22, Frontend, undefined"
Можете ли подробнее объяснить как использовать доп параметры?
Автор объяснил понятнее за 11 минут, чем Кантор, которого я полдня читал и не понял до конца!
Кантор в новой редакции совсем не сахар.
Там такая дичь. Так сложно написано(
@@ihorpopovskyi4862 это по-началу сложно, просто каждый день читай статьи, гугли и ютубь, ну и пробуй свой код писать и смотри что происходит. Со временём мозг сам поймёт чо-как, будешь к этому хладнокровно относиться и молча делать всё правильно и без эмоций.
@@indigosay Ты не понял, я конкретно про эту тему, а в основном там гораздо проще чем на MDN, например)
@@ihorpopovskyi4862 на MDN сухая инфа чисто повторить то, что ты чуть-чуть позабыл,. имхо
стоило сказать, что apply или call можно было использовать при написании кастомного bind )) в остальном отличное видео
Огромное спасибо за такой ценный free материал! Есть маленькая просьба, для таких новичков как я, было бы очень ценно понимать в каких случаях применять полученные знания. Пара примеров из реальной жизни.
там как раз и были наведены примеры из реальной жизни, например urlGenerator
Отдельное спасибо за примеры использования, не всегда понятно где и как реализовать ту, или иную особенность. 👍
Вот +++
Коротко, понятно + практика... Как итог - отличный урок. В общем как всегда.
Это талант так легко и просто объяснять вещи. Спасибо!
В конце блоки со ссылками на другие видео перекрывают экран и не видно кода.
чувак, ты же хочешь стать разработчиком. Возьми и тупо отключи рекламные блоки в панели разработчика.
@@olegonkos спасибо, чувак
@@olegonkos лучше поздно, чем никогда
@@olegonkos Это только до тих пор пока не перезагрузить страницу. Ну или селектор вкинуть в фильтры addblock
##.ytp-ce-element - да вот такой фильтр нужно добавить в addBliock и он сам зарежит эти рекомендации
Что-то я не совсем понял.
Каким образом заполняется параметр с массивом ...args в замыкании?
В bind передается контекст ( объекты ) и функция.
А дальше как замыкающая получает параметры ?
Да там ...args вообще по сути не нужен...
Должно было быть так:
function logPerson() {
console.log(`Person: ${this.name}, ${this.age}, ${this.job}`);
}
function bind(context) {
return (fn) => fn.apply(context);
}
const person1 = { name: "Михаил", age: 22, job: "Frontend" };
const person2 = { name: "Елена", age: 19, job: "SMM" };
bind(person1)(logPerson);
bind(person2)(logPerson);
Очень хорошо! Исчерпывающая информацию + сразу же можно выполнить самостоятельное задание и тут же его проверить. Большое спасибо автору, за возможность подтянуть свои знания!
Спасибо за видео! До момента, когда откуда-то появились ARGS было все понятно.
Красавчик, видео одно за другим!
Главное не сбавлять темп)
Мне кажется что в этом видео пропустили самый главный момент, без которого замыканий не существовало бы - вы пропустили момент создания лексического окружения, которое выполняется каждый раз при вызове функции
наверное чтобы не усложнять и так сложную тему.
@@crn05 это центральный момент, на котором все работает... буквально, кроме этого ничего нет
@@crn05 усложнять? Тебе в видосе показали примеры не объяснив как работает. При этом объяснение темы заняло бы 5 минут и уже не нужны бы были эти подливные примеры из любой статьи на 11 минут. На собесе если спросят то спросят именно в контексте окружения и т.д, а не на примеры "функции внутри функции" смотреть будут
Исходные данные задачи в конце ролика:
function logPerson() {
// console.log(`Person: ${this.name}, ${this.age}, ${this.job}`)
// }
// const person1 = {name: 'Михаил', age: 22, job: 'Frontend'}
// const person2 = {name: 'Елена', age: 19, job: 'SMM'}
// bind(person1, logPerson)
// bind(person2, logPerson)
Нечитабельная срань же.
@@khoth1988 что тебе нечитабельно? условия задачи, которые достаточно скопировать и использовать для решения?
@@Ghost15NG замыкания.
Ещё интересно было бы про AJAX, c практикой, короче скоро это будет топовый канал на ютубе с годными уроками по фронту))
XMLHttpRequest (XHR), AJAX, REST и тд жду!!!
В моде FETCH , Socket.io. REST API да, нужная штука.
Премию оскар за лучшее русскоязычное объяснение javascripta )
На самом деле, Вы большой молодец, Владилен)) Спасибо!
Спасибо большое за этот плейлист! 👍👍😊
Огромное Спасибо! я понял наконец-то что такое замыкание. Надеюсь ты продолжишь снимать ролики, они отличные!!!
Самое доступное объяснение. Спасибо большое за труд!
Большое Вам спасибо за такое подробное и простое объяснение!
Замечательное объяснение. Спасибо!
Кайф! Тяжело найти в инете такое понятное объяснение. Спасибо!
Ваш контент из русскоязычного один из лучших, что я видел/читал.
Благодарю)
Лучшее объяснение замыканий в JavaScript, что я слышал
Чувак, огромная благодарность!) Великолепно объясняешь!
Ты лучший. Наконец стал понятен смысл замыканий
Действительно простым языком. Спасибо за материал, помогли разобраться!
Лаконично!!👍👍👍 без воды и с реальными примерами
Не скажу ничего нового... Ты просто великолепен) Даешь окрепнуть в понимании нативного js так, как не делают другие и близко... На очереди приобретение курса по Node. Спасибо за все твои труды
объясняешь великолепно
я наконец-то понял, что такое замыкание , спасибо тебе огромное 🚀
круто все. Было здорово посмотреть твой урок по созданию JAVASCRIPT плагина.
Владилен, спасибо за классный контент - подача и материал, всё на очень высоком уровне.
В некоторых комментариях здесь утверждается, что в видео идет речь о функциях высшего порядка а не о замыканиях.
То что это функция высшего порядка, не отменяет тот факт , что здесь также присутствует замыкание:
1. Так как для функции внешним окружением является место, где она была объявлена, а не место
где она была вызвана, то в нашем случае анонимная функция которую мы возвращаем как результат выполнения
функции bind,получит в качестве ссылки на внешнее лексическое окружение, ссылку на лексическое окружение самой
функции bind.
При этом, эти ссылки сохраняются в так называемой куче(heap), что позволяет им, в отличии от непосредственно самой
функции, выполняющейся в стеке и удаляющейся оттуда сразу после того как функция завершит свою работу, оставаться в
памяти до удаления сборщиком мусора.
2. К лексическому окружению функции относятся не только ее параметры, но и аргументы. Поэтому, в нашем случае
и context и fn также входят в лексическое окружение функции bind.
Теперь, если:
const func = bind(person1,LogPerson)
то :
при вызове func(), произойдет следующее:
для получения context и fn функция сначала обратиться к своему лексическому окружению,
так как их там нет, то она по имеющейся у неё ссылке начнёт поиск в лексическом окружении внешней функции,
где она была объявлена, именно этот момент и есть замыкание.
Вот мои два варианта решения задачи:
Для чистоты эксперимента, сделал функционал как у оригинального bind, без явного добавления функции в параметры
и чтоб совсем все было своим, функцию apply также сделал кастомной:
_________________________________________________________________________
Object.prototype.myApply = function (context,args) {
if(!Array.isArray(args)) throw new Error('parameter is not Array');
const tempContext = {...context, appliedFunc: this};
tempContext.appliedFunc(...args)
};
Object.prototype.myBind = function (context,...args) {
const boundFunc = this;
return function () {
boundFunc.myApply(context,args)
}
};
logPerson.myBind(person1)()
_________________________________________________________________________
Или другой вариант, наиболее оптимальный, объединяющий эти две функции:
_________________________________________________________________________
Object.prototype.myBind2 = function (context,...args) {
const tempContext = {...context, boundFunc: this};
return function () {
tempContext.boundFunc(...args)
}
}
logPerson.myBind(person2)()
_________________________________________________________________________
------------- Базовая функция ------------
logPerson.bind (p1)( )
вывод:
Person: M, 22
this: {name: 'M', age: '22'}
age: "22"
name: "M"
[[Prototype]]: Object
------------- Ваш пример ------------
logPerson.myBind2 (p1)( )
вывод:
Person: M, 22
this: {name: 'M', age: '22', boundFunc: ƒ}
age: "22"
boundFunc: ƒ logPerson()
name: "M"
[[Prototype]]: Object
------------- Мой вариант я без аргументов делал, но добавить их не сложно ------------
bind (p1, logPerson)( )
вывод:
Person: M, 22
this: {f: ƒ}
f: ƒ logPerson()
[[Prototype]]: Object
age: "22"
name: "M"
[[Prototype]]: Object
Реализация, тоже думал что apply и call пользовать не положено
function bind(obj, func) {
const nobj = {f: func};
Object.setPrototypeOf(nobj, obj);
return (function() {nobj.f()});
}
А вот так легко call можно сделать
function bind(obj, func) {
const nObj = {f: func};
Object.setPrototypeOf(nObj, obj);
nObj.f();
}
А почему ни слова об областях видимости переменных во вложеных функциях? Мне кажется это тоже важно в данном контексте.
а что там поменялось ?
@@andTutin var задизили, стрессует
а об этом ты узнаешь если купишь курс! и там тебе дадут новое видео где раскроют твой вопрос, но не скажут ещё о чем-нибудь, об этом тебе расскажут уже в следующих купленных видео )) и так до тех пор пока ты не поумнеешь и не начнёшь читать книги по js'у))
@@epic3386 уже работаю в Оракле, так-что не актуально )
Мои искренние поздравления )) видимо начал читать книжки?))
ОЧЕНЬ ХОРОШО ОБЪЯСНИЛИ. СПАСИБО
Хочу сказать что твой контент очень крутой! Наконец то не тот контекст как объявлять и складывать переменные а именно то что нужно.
Спасибо, это лучшее объяснение.
Отличный контент, спасибо большое)))
Лучший способ научить - самый простой!
Спасибо, переплюнул 90% инфы на эту темую
я вот просто, благодарен за твои уроки!!!!!!!!!!!
Спасибо тебе, Ленин, ты крут!
прекрасный урок, спасибо 😊
Браво! Все супер понятно! Спасибо!
Отличный контенет. Спасибо
Спасибо за урок!
Спасибо) отличное объяснение!!
Как уже писал кто-то ранее, первые два ролика прям доходчиво, тут пример в конце выбивает из колеи понимания.
Владлен, у тебя ахрененный канал. Побольше бы таких))
Благодарю)
10:50 Оператор Rest, а не Spread в данном случае. Spread используется для разделения коллекций на отдельные элементы, а rest, наоборот, для соединения отдельных значений в массив.
Всё ясно и понятно. Спасибо.
Спасибо за хорошее объяснение.)
О боги,я понял это спустя неделю попыток и тонны лит-ры и видео) Прикладные примеры - самое важное,за это отдельное спасибо!
@@ne4to777 Почему ты так уверен?)
@@ne4to777 Ну не в развернутой форме, очевидно (формат не подразумевает)
Но все же, базовое понимание видео дало
Спасибо большое за объяснение!
Но всё же не совсем понятно, зачем в данном случае нужно замыкание. Можно ведь в рамках одной функции всё сделать:
function bind(context, fn) {
return fn.call(context)
}
Какой практический смысл здесь в замыкании?
там даже return не нужен
тогда ведь теряется смысл, который заложен в оригинальный bind: сначала указывается контекст, затем вызывается. Собственно, замыкание в этом случае и служит как раз для "отложенного" вызова.
Спасибо за уроки, отличное качество.
Благодарю за отзыв)
Ознакомься с другими роликами на канале
@@VladilenMinin Я знаком, спасибо и буду знакомиться дальше). Удачи в делах!
Шикарная информация!
Отличный урок!
Комментарий из восьми слов для поддержки этого видео.
Вообще лучшее объяснение!
спасибище, реально все четко и понятно!
Примеры и задачи должны решаться с замыканием проще и изящней, чем без него. Иначе вопрос "зачем" остается не раскрыт. А по механике все очень доходчиво.
Спасибо. Именно у вас понял.
Спасибо за видео!
На мой взгляд стоило сделать немного иначе.
function bind(fn) {
return function(context) {
fn.apply(context)
}
}
const personData = bind(logPerson)
Получили функцию, возвращающую данные любого человека.
Довольно простая тема, если по человечески её объснить) Спасибо, наконец-то понял на 100%
@@ne4to777 это когда функция получила внешнюю переменную и забыла про внешнюю)
@@ne4to777 ага. работает с ней как с копией)
Спасибо вам за видео
Спасибо. С 4-ого раза просмотра видео, мне всё же удалось, самому написать функцию bind работающую.
На канале есть подробный ролик про его создание)
я что-то не вкурил про аргументы. они ведь не передаются. откуда они появляются ?
а с учетом первичного задания, все вообще сводится до fn.apply(context)()
Там не аргументы появились, а поля объекта из контекста. Я так понял параметры функция принимает, потому что спроектирована с запасом на разные ситуации.
Они появляются от rest params
Спасибо за урок
офигенный урок
Добрый день, подскажет пожалуйста, а вложеная фукция ведь может быть стрелочной? И если да то будет ли она работать так же как и с обычным декларированием? И нет ли каких-то подводных камней с использованием this в обоих случаях. Спасибо
Спасибо большое за урок. Только есть вопрос про последнее действие.
Понятно что метод apply() должен обязательно иметь два параметра, но что имеется ввиду под массивом ...args ? не понял зачем нужно передавать внутри второй функции ещё какие-то параметры, если функция bind требует только обьект для контекста (person) и саму функцию вывода (logPerson) информации в консоли ?
далее: callback, promise, async/await.
Огромное спасибо! Шедевральное обьяснение с примерами. Как минимум, можно будет обьяснить на собеседовании принцип работы или написать самому, а не пытатьсчя заучивать непонятные словешки)))
четко объяснил, спс
Спасибо! Наконец Я понял замыкание полностью 😂
Большое спасибо Автору за: показал зачем оно в практическом смысле надо. А то остальные только счетчик показывают и всё
Страшная тема для соло-обучения в онлайн-учебниках. В статье со скопом из "контекста", "лексического окружения" и "сборщика мусора" - можно впасть в депрессию. Напоминает мене, как меня в колледже учили "что такое транзистор" в течении целого года + курсовая по ним. Ну и тот самый страх, при мысли того, что тебе когда-то придётся его использовать. Так сильно заваливать информацией, когда это можно обьяснить так просто.
Спасибо за ваш ролик. Какой же всё-таки талант - уметь обьяснять вещи просто.
годнота!
Самое интересное в замыканиях то, что я как-то всегда боялся этого слова, казалось что это какой-то хитровыдуманный и сложный программистский концепт. А когда понял что это такое, оказалось я сам неоднократно использовал его в своем коде даже не подозревая, чисто на интуитивном уровне.
такое часто бывает, пользуешься чем-то, а оказывается у этого страшное название есть
Вот вам детки задачка по математике из 1 класса школьной программы. Поняли? Отлично! Вот пример из 2 класса школьной программы. А вот из 3 класса. Усвоили? Замечательно, молодцы!! А теперь поставьте видео на паузу и самостоятельно решите задачку которую дают на олимпиадах по математике для 11 класса)))))) Не можете? Сейчас вместе разберём... И на самом интересном месте вылетает реклама закрывающая треть экрана))))))))))) Владлен, моё к вам уважение! Ваши уроки хороши, но понять их порой крайне не просто.
Привет, отлично!
замыкание - функция внутри функции и все! гениально
Нет не все ибо замыкается область видимости родительской ф-ции, в этом и весь смысл, а не просто "функция в функции" и дочерняя ф-ция сохраняет доступ к этой видимости (переменным родительской ф-ции).
@@zxspectrum3352 Именно так. А утверждение замыкание это вызов функции в функции не верно
Не уверен, что этимология верна, но подача удобная.
толково объяснил
Кто-то пишет ,что сложно и не понятно😂 но по мне это самое крутое обьяснение замыкания которое я видел
понял. Спасибо!
По последней задачки думаю нужен апдейт:
Функция bind в вашем примере создает "обертку" вокруг функции fn, которая при вызове устанавливает this в переданный контекст context. Это позволяет вам вызывать функцию fn так, как если бы она была методом объекта context.
Давайте разберемся, как это работает, шаг за шагом:
1. bind принимает два аргумента: context и fn.
2. bind возвращает новую функцию, которая при вызове будет применять функцию fn к контексту context.
3. Когда возвращенная функция вызывается, она использует ...args для сбора всех переданных аргументов в массив args.
4. fn.apply(context, [args]) вызывается внутри этой функции. Метод apply используется для вызова функции fn с конкретным значением this (в данном случае context) и массивом аргументов args.
В вашем конкретном случае использование ...args и [args] вокруг args не имеет смысла, поскольку logPerson не принимает никаких аргументов, и использование apply с массивом аргументов в этом случае избыточно. Это может быть полезно, если бы функция logPerson принимала дополнительные параметры.
Тем не менее, чтобы функция bind работала корректно с функцией logPerson, которая не принимает аргументы, вам нужно вызвать fn.apply(context) без второго параметра или использовать пустой массив для аргументов:
function bind(context, fn){
return function(){ // здесь args не нужны, так как logPerson их не принимает
return fn.apply(context); // вызываем fn с контекстом context и без аргументов
}
}
bind(person1, logPerson)(); // Person: Misha, 22, Frontend
bind(person2, logPerson)(); // Person: Lena, 18, SMM
Использование ...args и [args] имело бы смысл, если бы вы хотели, чтобы функция bind могла принимать и передавать любое количество аргументов в функцию fn, но в вашем текущем примере это не требуется.
Здравствуйте)
Все очень круто и интересно, но я столкнулась с такой проблемой: на странице в браузере, в консоли выводятся только ошибки, а мой редактор (Brackets) ругается на rest, то есть правильный код просто не проигрывается, хотя js файл подключен правильно, проблема не в этом. Синтаксических ошибок тоже нет. Можете подсказать пожалуйста, в чем дело может быть?
Зачем или какой толк в замыкании , например в примере с url ?
Если мы можем сделать одну функцию с двумя аргументами , function(url,domain) и тд ....
спасибо за объяснения , понял , как работает , но не понял зачем ))
Гибкость. Допустим создаешь переменную с ru доменом. И потом спокойно подставляешь туда только название сайта, вызывая нужную переменную. А так тебе придется постоянно писать "ru", что не очень хорошо.
А еще, в этом уроке не показано, но классность в том, что в функции обертке, ты можешь задавать переменные и они у тебя будут хранится там, а не в глобальном поле.
Супер!!!
Владилен, спасибо. Я вот одно не пойму, зачем bind в методах классов, если метод вызван через this. Почему контекст может потеряться?
Очень годно))
Спасибо!
Спасибо за урок! Не понял только в конце в функции bind в возвращаемую функцию мы передаем args и их потом в метод apply. Как и где на практике мы можем передать эти аргументы в возвращаемую функцию? Сейчас функция bind работает и без этих аргументов
плюсую, до меня вообще долго доходило что в примере мы это место не используем
Тоже не понял - для чего в примере ...args ?
Спасибо за данный плейлист, его ценность сложно переоценить, БЛАГОДАРЮ!!!
Идея с задачками в конце просто отличная) Т к не хватало практики.
БУДУ РАД ЕСЛИ КТО-ТО МНЕ ОБЬЯСНИТ ЗАЧЕМ В ЗАДАЧКЕ ВООБЩЕ ...args =)
Только вот я не понимаю зачем в конечной задачке вообще замыкание и какие еще параметры вы собираетесь туда передавать, этого в условии задачи не было. Можно просто вот так сделать и так же будет все работать:
function bind(context, fn) {
return fn.apply(context)
}
bind(person1, logPerson)
bind(person2, logPerson)
Поэтому необходимости и смысла использования замыкания в данном примере к сожалению я не увидел, хотя хотелось применить как-то это знание. А тут по сути просто мы воспользовались альтернативой .bind(), вместо того, чтобы написать свою функцию. ИМХО.
тоже не поняла зачем args нужен
спасибо за обьяснение. Но хотел бы узнать какой у тебя ноутбук? Так как хочу купить себе новый, потому что мой уже начинает гнать
Владилен, снимаю шляпу!) Прекрасно объясняешь теперь. Не то, что в курсах платных (если честно, не понимаю почему), может просто опыт преподавания растёт))) Так держать! То же и про .bind и .call.
Опыт да. Владлен норм так начал рассказывать. И по делу и голос приятен.
Хз по моему платные курсы у него тоже отличные
Не понял зачем args в данном случае, разве на случай, если захочется еще какие-то доп.параметры консолить, не предусмотренные в объектах person. Задача ведь решается без них, точно также можно было и call вписать. И спасибо за задачу, заставил немного напрячь мозги!
Ты лучший фронтенд блогер. И я могу обосновать это. Во-первых: за такой короткий промежуток времени ты создал огромный канал с исчерпывающей информацией по фронтенд разработке. Во-вторых: любой человек с желанием может просто внимательно смотря твои видео по порядку и выполняя вместе с тобой задачи научиться всему за кратчайшие сроки. Все это благодаря структурированности и продуманности каждого плейлиста и видео. Я боюсь представить скольких усилий это все тебе стоило. В-третьих: все видео без лишней воды, и неуместных рофлов. В-четвертых: на этом канале я не увидел ни одного видео ради видео, каждое видео отличается от другого и раскрывает разные темы. В-пятых: четкая дикция, отлично выступаешь на камеру. Ты на верном пути братан, продолжай
Благодарю за такой отзыв, мне очень приятно)