Декларация языка javascript позволяет сделать очень много комбинаций из разнообразных выражений и по мнению компилятора/интерпретатора все они будут вполне законны и будут выполняться без ошибок.
Некоторые из них хорошо описаны в статье Ниндзя-код, но пару дней назад мне попался не знакомый мне вариант, который заставил меня усомниться в моих знаниях javascript
Вот этот код (страничка в браузере):
<body>
<script>
window.myproj = {};
window.myproj.func1 = () => {
alert(getFirstName());
}
</script>
<script>
window.myproj.func2 = () => {
myproj.func1(
getFirstName = () => { return "Alex"; },
);
}
</script>
<script>
window.myproj.func2();
</script>
</body>
Можно ли по коду сказать что покажет в диалоге func2?
Я не смог.
Заранее, перед просмотром этого кода я уже знал, что он работает без ошибок и показывает текст "Alex". И рассчитывал на быстрое "ревью".
И проглядев строчки этого кода я уже было решил, что это корректный код, но вдруг обратил внимание на странный вызов, где вроде бы у функции должен был быть аргумент:
window.myproj.func1 = () => {
alert(getFirstName());
}
Но аргумента не было. Вместо него была "просто переменная". И по коду мне было совершенно не понятно откуда она появилась в этом блоке "<script>", почему при выполнении не было ошибки навроде "unknown variable" и как переменная смогла возвращать правильное значение.
Однако код выполнялся без ошибок и показывал правильный текст. Вот тут я начал сомневаться в своих знаниях языка и запустил отладку.
И уже под отладкой действительно узнал кое-что новое.
js компилятор позволяет на месте для параметра функции написать много разных выражений.
"Присвоение переменной" - это одно из таких выражений (значение переменной компилятор передаст дальше как значение для аргумента функции)
Присвоение переменной без явного объявления сделает новую переменную где-то на высоком уровне (это называется "hoisting")
В моем коде высоким уровнем будет window.
Свойства window доступны без префикса 'window.getFirstName' и можно писать сразу 'getFirstName'.
Поэтому переменная getFirstName возвращает верное значение и показывается правильный текст.
Т.е. в моем коде аргументы функции вообще ни капли не используются. Использованное расположение кода с присвоением значения в переменную на месте, где обычно пишется аргумент функции, маскирует декларацию новой глобальной переменной и присвоение в нее значения, что бы все выглядело так, как будто в коде делается передача именованного аргумента.
Я сначала это так и читал как "именованное присвоение значений в конкретные аргументы функции". В cs есть такое и в js похожий синтаксис. Мои глаза уже привыкли, что если код разбит на строки как в моем примере и на месте для аргумента функции есть присвоения, значит это присвоение в аргументы. Я даже не вчитывался в символы в этом коде.
И долго не видел, что тут нет никакого "именованное присвоение" и не мог понять без отладки как этот код вообще успешно работает.
В моем проекте по коду должно быть понятно как он работает и для понимания не должны требоваться какие-то специальные знания (например "hoisting"). Технические ньюансы в коде должны быть очевидны и я переделал код с "hoisting" на явную передачу аргументов:
<body>
<script>
window.myproj= {};
window.myproj.func1 = ({ getFirstName }) => {
alert(getFirstName());
}
</script>
<script>
window.myproj.func2 = () => {
myproj.func1({
getFirstName: () => { return "Alex"; },
});
}
</script>
<script>
window.myproj.func2();
</script>
</body>
В этом варианте в коде написано именно то, что видно при беглом просмотре: передача аргументов в функцию и внутри функции обращение к своим аргументам.
Комментариев нет:
Отправить комментарий