X   Сообщение сайта
(Сообщение закроется через 3 секунды)



 

Здравствуйте, гость (

| Вход | Регистрация )

4 страниц V   1 2 3 4 >
Открыть тему
Тема закрыта
> Область видимости функций JS
ShowPrint
ShowPrint
Topic Starter сообщение 5.12.2017, 18:54; Ответить: ShowPrint
Сообщение #1


Hi, all!

Продолжая изобретения велосипедов знакомлюсь всё с новыми и новыми особенностями JS и ему подобных.
Столкнулся с проблемами связанными с областью видимости функций внутри скриптов.

У меня для каждой страницы получается два файла скриптов: первый - общий для всех, второй - индивидуальный для страницы.
Собственно чтоб не грузить лишнего и не раздувать в размере "общий".
Получается что "общий" при переходе со страницы на страницу грузится из кеша и догружает небольшой "индивидуальный".
"Общий", дабы быстрее выдать страницу посетителю, отрабатывают по событию document.ready

Условно "общий" скрипт следующего вида:

$(document).ready(function(){ // ждём окончания загрузки страницы
var ... // переменные
function myFunc(){...} // ряд пользовательских функций и операций
$.ajax({
url:'/script/local.js', // загрузка "индивидуального" скрипта
cache:true,
dataType:'script',
success:function(){
// после загрузки производим всякие манипуляции
}
});
});

Ну и "индивидуальные" скрипты совершенно обычные - какие-то манипуляции, навешивание и обработка событий и прочая лабуда.

Гимор заключается в следующем:
Периодически в "индивидуальных" скриптах приходится использовать пользовательские функции, созданные в "общем" скрипте (myFunc из примера), а эти функции получаются невидимыми в подгружаемых скриптах. То есть в них 

alert(typeof(myFunc));

 выдает результат undefined

Методом тыка и экспериментов нашел два варианта решения проблемы:
  1. из "основного" скрипта убрать первую строку ( $(document).ready(function(){...}); ), но это откладывает отсрочку события окончания загрузки страницы, что не очень-то греет душу (

  2. в "индивидуальном" скрипте продублировать функцию, что и увеличивает размер скрипта, и как-то неправильно.

В общем, оба найденных варианта получаются как-то не по феншую  :(

Собственно вопрос: есть-ли какие-то варианты более изящного решения?
Логически предполагаю, что должно быть какое-то решение, либо в виде сделать "функцию myFunc глобальной" - видимой во всех подгружаемых (индивидуальных) скриптах, либо возможность передачи функции подгружаемым скриптам в виде объекта.

Прошу содействия в виде подсказки или ссылки где поискать и что почитать (желательно с примерами). Может хоть правильное название какого-нибудь правильного слова которое можно загуглить... Кто-чем может, плз...
[offtopic]
Гуглил достаточно много, но натыкался в основном на различные описания теории по JS "замыканиям" и "инкапсуляции". Если теорию по "замыканиям" хоть как-то понимаю, то с инкапсуляцией пока разобрался не очень.
Мой моск устроен своеобразно - теорию усваиваю только если рассматриваются практические примеры. А с примерами не очень всё хорошо - большинство однотипных и, что самое сложное, далеки от моей задачи, а как "прикрутить" эту теорию к решению своей задачи без примера совсем не пойму. :wacko:
Моет быть потому что замыканиями и инкапсуляцией мою задачу не решить и надо что-то другое искать? (что именно?) :unsure:
[/offtopic]
0
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
ixman
ixman
сообщение 5.12.2017, 20:41; Ответить: ixman
Сообщение #2


Михаил, не знаю в тему или нет, но может стоит потыкать так. Так как у меня ощущение такое, что индивидуальный загружается раньше общего и из-за этого не видит общих функций. Нэ?
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
fedornabilkin
fedornabilkin
сообщение 5.12.2017, 21:06; Ответить: fedornabilkin
Сообщение #3


Правильное название правильного слова - LexicalEnvironment или лексическое окружение.
Если ты используешь document.ready, то аргументом передаешь в него анонимную функцию.

$(document).ready(function(){var foo; myFunc(){}});

Тоже самое, только по полочкам:

var other = readyFunc(){
var foo;
myFunc(){};
};

$.document.ready(other);

Так вот у myFunc() свое лексическое окружение, которое не выходит за рамки readyFunc().
Тоже самое происходит, когда ты грузишь свои скрипты аяксом (если честно, странноватое решение). Я не думаю, что у тебя гигантский проект и возникает необходимость догружать апосля. При чем обычно скриптовые файлы кэшируются браузерами и запрос на сервер не отправляется. Как правило, скрипты подключаются в конце страницы, чтобы не мешать отрисовке.

Так вот $.ajax() принимает объект, в котором success присваиваем анонимную функцию для получения ответа от сервера. Следовательно все твои индивидуальные видны внутри анонимной функции.

Один из вариантов решения (сам не пробовал).
В общем файле создаешь объект с необходимыми функциями и потом верти ими как хочешь, главное правильно начать. Запустишь, посмотри логи.

var myGlobalFunctions = function(){
var cache = {}; // для каждого экземпляра своя переменная (замыкания - это отсюда начинаются)
return {
first: function(arg, varg){
return arg + varg;
},
second: function(iname, fname){
return 'Привет, ' +iname+ ' ' +fname;
},
setCache: function(key, val){
cache[key] = val;
},
getCache: function(key){
if(!key){
return cache;
}
return typeof cache['key'] !== "undefined" ? cache['key']: null;
}
};
};

$(document).ready(function(){
var myLocalFunc = myGlobalFunctions(); // получаем в переменную список функций
var res_second_func = myLocalFunc.second('Имя', 'Фамилия'); // вызываем необходимую функцию
console.log('second', res_second_func); // зырим, что получилось

// сохраним значение в кэш
myLocalFunc.setCache('name', 'Имя');
// позырим, что в кэше
console.log('myLocalFunc', myLocalFunc.getCache());

// можно создать второй комплект (он совершенно новый и с чистым кэшем)
// с таким же набором функций и передать его куда угодно или использовать по своему усмотрению
var yourLocalFunc = myGlobalFunctions();
// кэш пустой
console.log('yourLocalFunc', yourLocalFunc.getCache());

// шлем аякс и внутрях видим переменную myLocalFunc,
// потому что она глобальна в пределах анонимной функции document ready

// $.ajax({
// url:'/script/local.js', // загрузка "индивидуального" скрипта
// cache:true,
// dataType:'script',
// success:function(){
// // после загрузки производим всякие манипуляции
// // myLocalFunc тут доступна
// }
// });
});

Самое главное стараться не писать таких функций, которые вызывают себе подобных, чтобы память не утекала. На обычных страница это не особо критично, но к плохому быстро привыкаешь.
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
ShowPrint
ShowPrint
Topic Starter сообщение 5.12.2017, 22:04; Ответить: ShowPrint
Сообщение #4


( @ 5.12.2017, 23:41) *
у меня ощущение такое, что индивидуальный загружается раньше общего

Иван, я так не думаю...  :( (учебник по ссылке: "настольная книга" - всегда открыт в отдельной вкладке браузера, также как форум  :D )


Из "эйчтиэмэля" общий скрипт гружу также аяксом в асинхроне:

<script>
$.ajax({url:'/script/main.js',cache:true,dataType:'script'});
</script>

"Локальный", в случае необходимости, грузит основной также асинхроном (насколько я понимаю - образно говоря параллельным потоком), но уже после объявления пользовательской функции, которая является уже созданным объектом.
Пробовал переделать объявление функции через var - не помогло, результат тот же...

"Не думаю", т.к. не понимаю следующей логики - когда скрипт выполняется без ожидания окончания загрузки дерева DOM, то он работает... Здесь что-то с "видимостью" не так...

О... Аха... Вот и Федор написал умных слов!!!...


( @ 6.12.2017, 00:06) *
Правильное название правильного слова - LexicalEnvironment или лексическое окружение.

Значит правильные слова я нашёл верно, про лексическое окружение и читал... Не до конца сложилось в голове понимание, но с твоим примером буду пробовать колдовать и сложить аккуратный стог в голове, чтоб не торчало в разные стороны...



( @ 6.12.2017, 00:06) *
у myFunc() свое лексическое окружение, которое не выходит за рамки readyFunc()

То есть содержимое local.js не видит лексического окружения в котором создана myFunc даже не смотря на то, что этот local.js загружен тем самым лексическим окружением? Так?


Получается, что если я съел конфетку - она еще не стала частью меня самого? В этом ошибка? Если да, то как-то неправильно получается: я же не стырил конфетку, я её достал из своего же кармана...  :(

Я вычитал вот это (по ссылке выше)
Интерпретатор, при доступе к переменной, сначала пытается найти переменную в текущем LexicalEnvironment, а затем, если её нет – ищет во внешнем объекте переменных. В данном случае им является window.

Такой порядок поиска возможен благодаря тому, что ссылка на внешний объект переменных хранится в специальном внутреннем свойстве функции, которое называется [[Scope]]. Это свойство закрыто от прямого доступа, но знание о нём очень важно для понимания того, как работает JavaScript.


При создании функция получает скрытое свойство [[Scope]], которое ссылается на лексическое окружение, в котором она была создана.


Просто я решил, что если в лексическом окружении local.js не нашлось myFunc, то он найдёт её "во внешнем объекте переменных", то бишь "внешним" я посчитал основной скрипт...

Буду пробовать разбираться с предложенным вариантом решения, это вполне понятный пример. Если бы я насерфил такой, то не было бы топика, но увы...

Сразу после беглого просмотра и осмысления вопрос: правильно я понимаю, что функции setCache и getCache типа "отладочные" и нужны для проверки работоспособности? (в смысле "после отладки можно удалить безболезненно?")

fedornabilkin, гранд-мерси за пример!!!  :smile-thumb-up:

[offtopic]

( @ 6.12.2017, 00:06) *
странноватое решение). Я не думаю, что у тебя гигантский проект и возникает необходимость догружать апосля.

Да, неееее... Проект микроскопический, но врождённый перфекционизм - гигантский... Просто нутро восстаёт против того, чтоб грузить сразу все скрипты, включая те, которые используются на страницах до которых посетитель может и не дойти в принципе... А если дойдёт - основной скрипт заберёт из кеша и догрузит крохотный...  :)

Да и мне проще ворочать несколько мелких, чем одну "простыню" когда что-то надо поменять...
Да и при изменениях "индивидуальных" посетитель может получить основной из кеша, а не грузить "простынь" в которой поменялась одна буква...
Возможно и лишнее совсем, но корябать хочется так, чтоб результат приносил удовольствие и не вызывал когнитивный диссонанс...
Против собственной воли и потребности не очень хочется идти, другое дело если это - "зло", тогда нутро прислушается и само своё отношение поменяет  :lol:
[/offtopic]
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
fedornabilkin
fedornabilkin
сообщение 6.12.2017, 10:27; Ответить: fedornabilkin
Сообщение #5


(ShowPrint @ 6.12.2017, 01:04) *
Сразу после беглого просмотра и осмысления вопрос: правильно я понимаю, что функции setCache и getCache типа "отладочные" и нужны для проверки работоспособности? (в смысле "после отладки можно удалить безболезненно?")

Да нет, они вполне себе самые обычные функции, которые можно использовать для записи и получения данных. Но, если нет им применения, то можно и удалить.

С конфетой все правильно, только сложность в том, что ты ее можешь достать только из одного кармана. Из других карманов конфета будет недоступна. А когда ты ее съел (передал в переменной), то она уже доступна для всего организма.
(ShowPrint @ 6.12.2017, 01:04) *
Просто я решил, что если в лексическом окружении local.js не нашлось myFunc, то он найдёт её "во внешнем объекте переменных", то бишь "внешним" я посчитал основной скрипт...

Так и есть, искать будет во внешнем, но ее там нет, потому что она внутрях другой функции. Пришел в магаз и не нашел конфету на локальном прилавке. Логично, что конфету надо искать во внешнем складе, а не на соседнем локальном прилавке. 
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
ShowPrint
ShowPrint
Topic Starter сообщение 6.12.2017, 16:22; Ответить: ShowPrint
Сообщение #6


(fedornabilkin @ 6.12.2017, 13:27) *
но ее там нет, потому что она внутрях другой функции
Именно поэтому называется "замыкание"? потому что нет связи "родитель-потомок"? если инициировал загрузку, то это не означает что загружено будет в лексическое окружение инициатора?
[offtopic]Получается как в жизни: если воспитываешь ребенка, то не факт что именно ты его отец  :lol: [/offtopic]

Федор, а есть в природе варианты явяскриптом подтянуть внешний скрипт в своё же лексическое окружение? может не через $.ajax и не через $.getScript - на самом деле после того как я основной запускаю по окончанию загрузки DOM и в асинхроне, то пофиг как он будет подтягиваться - всяко получится асинхрон... какой-нить вариант типа пыховой include/require?

Я просто рассматривая всякие js скрипты обращал внимание на то, что встречаются вещи типа объявления функций взятые в скобки (инкапсуляция?) или ещё объявление начинающееся с восклицательного знака...
Или это всё уже из совершенно другой оперы и не стоит мне как любителю лезть настолько глубоко?
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
fedornabilkin
fedornabilkin
сообщение 6.12.2017, 23:13; Ответить: fedornabilkin
Сообщение #7


Я сейчас не совсем понял. Если хочешь использовать функции из общего файла в индивидуальном, то я написал пример. По идее должно работать. Если хочешь использовать функции из индивидуального файла в общем, то скорее всего что-то тут не так. Хотя есть еще колбэки (функции обратного вызова). Когда индивидуальный загрузится, то в колбэк передаешь функции индивидуального файла и пользуешься ими в общем. Соответственно все использование произойдет после загрузки. Такой вариант очень плохой, потому что быстро запутаешься.
Если я тебя не понял, напиши на пальцах, где какие функции и когда ты их хочешь использовать.
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
ShowPrint
ShowPrint
Topic Starter сообщение 6.12.2017, 23:33; Ответить: ShowPrint
Сообщение #8


(fedornabilkin @ 7.12.2017, 02:13) *
Я сейчас не совсем понял

Неее... Всё понял правильно и еще раз спасибо за помощь!
Просто я не понимаю логики почему общий скрипт инициируя загрузку индивидуального не подтягивает его в своё лексическое окружение.
Но видимо такова была задумка создателей JS и они руководствовались какими-то соображениями при этом. Соответственно самым правильным ответом на моё "почему" будет "потому что так"  :)

Я полез "в дебри" и пытаться разобраться с остальным. Видимо не даёт мне покоя отсутствие понимания принципа работы которое встречаю в виде функций обёрнутых в скобки. Вот и сейчас разглядываю, разбираюсь и пытаюсь понять одну из плюшек по ссылке на блог, которую "подкинул" Иван (тынц), вижу аналогичное обёртывание в коде с частью jQuery и наступает "бамц" (отсутствие понимания)

Забей... Буду реализовывать предложенный тобой вариант. Это так просто - не люблю тупо копипастить, предпочитаю понимать что делает код который я ставлю на сайт )))

UPD
( @ 6.12.2017, 19:22) *
а есть в природе варианты явяскриптом подтянуть внешний скрипт в своё же лексическое окружение ... какой-нить вариант типа пыховой include/require?

"На пальцах": имел в виду какой-то вариант чтоб интерпретатор начал заполнение лексического окружения, потом загрузил что нужно (в моём случае "индивидуальный" скрипт и потом продолжил формирование лексического окружения уже с этим загруженным скриптом  :D

Предвижу ответ "Много хочешь, мы не ищем лёгких путей"  :lol:

Сообщение отредактировал ShowPrint - 7.12.2017, 0:56
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
fedornabilkin
fedornabilkin
сообщение 7.12.2017, 15:39; Ответить: fedornabilkin
Сообщение #9


$.ajax это самостоятельная функция и у нее есть еще success, тоже самостоятельная функция. Когда грузишь скрипт, он появляется на два уровня ниже твоего общего лексического окружения. Поэтому ты не видишь функции индивидуального скрипта в общем окружении.
Пыховый include/require это вот твоя подгрузка ajax. Если хочешь заполнять лексическое окружение, вероятно, тебе подойдет прототипное наследование. Я такой подход использовал в SAR.
До сих пор сомневаюсь в целесообразности подгрузки скриптов ajax'ом. Не на то тратишь драгоценное время.
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
ShowPrint
ShowPrint
Topic Starter сообщение 7.12.2017, 15:42; Ответить: ShowPrint
Сообщение #10


fedornabilkin, большое спасибо, более-менее осознал, бум дальше разбираться! =)
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
4 страниц V   1 2 3 4 >
Открыть тему
Тема закрыта
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0


Свернуть

> Похожие темы

  Тема Ответов Автор Просмотров Последний ответ
Открытая тема (нет новых ответов) Нужна помощь по видимости ключевиков сайта
для тех, у кого есть аккаунт на мегаидекс или подобных сервисах
17 karambas 2250 1.2.2023, 9:33
автор: EvilGomel
Открытая тема (нет новых ответов) Вывод запросов в Топ. Повышение видимости сайта в ПС.
Оплата за результат! Топ от 500р./запрос. Видимость от 5000р./мес.
4 Blogir 3700 17.6.2017, 23:47
автор: Blogir
Открытая тема (нет новых ответов) ASK Spamer по ask.fm многопоточный + регер с парсером по онлайну и еще кучей полезных функций
15 Gad 8531 25.3.2017, 18:40
автор: Gad
Открытая тема (нет новых ответов) Продажа дополнительных функций на сайте.
0 DmitriyV 2517 14.10.2012, 18:52
автор: -DmitriyV-
Открытая тема (нет новых ответов) Смена картинки при наведении на ОПРЕДЕЛЕННУЮ область картинки
1 sevenmc 6518 28.8.2011, 19:49
автор: -SEVI-


 



RSS Текстовая версия Сейчас: 29.3.2024, 16:55
Дизайн