Как что-то кэшировать / предварительно вычислять (без глобальной переменной)?

#javascript

#javascript

Вопрос:

Что я хочу сделать, так это отправить данные между двумя обработчиками.

 element.onmousedown = function() {
    data = precalculate();
}

element.onmouseup = function() {
    dosomething(data);
}
  

если data это глобальная переменная, это работает. Люди говорят, что глобальная переменная — это зло. Но я не знаю, как обойтись без этого.

или я неправильно понял «глобальную переменную»?

Ответ №1:

Просто измените область видимости переменной, если вы не хотите / нуждаетесь в том, чтобы она была глобальной:

 (function() {
    var data;
    element.onmousedown = function() {
        data = precalculate();
    }

    element.onmouseup = function() {
        dosomething(data);
    }
})();
  

РЕДАКТИРОВАТЬ: Чтобы уточнить, единственный способ создать новую область видимости переменной в javascript — это использовать функцию.

Любая переменная, объявленная с var внутри функции, недоступна для внешней области видимости.

В приведенном выше коде я создал IIFE (выражение функции, вызываемое немедленно), которое представляет собой просто функцию, которая вызывается сразу после ее создания, и я поместил вашу data переменную (вместе с назначениями обработчика) внутри нее.

Поскольку обработчики были созданы в области видимости, которая имеет доступ к data переменной, они сохраняют свой доступ к этой переменной.

Чтобы привести другой пример:

 var a = "a"; // global variable

(function() {

    var b = "b";  // new variable in this scope

    (function() {

        var c = "c";  // new variable in this scope

        // in this function, you have access to 'a', 'b' and 'c'

    })();

    // in this function you have access to 'a' and 'b' variables, but not 'c'

})();

// globally, you have access to the 'a' variable, but not 'b' or 'c'
  

Комментарии:

1. @Lai: Рад, что смог помочь. Я добавил еще один пример области видимости переменной.

Ответ №2:

В этом случае глобальная переменная имела бы смысл. Другая возможность — присвоить значение элементу DOM:

 element.onmousedown = function() {
    // 'this' should point to the element being mouse downed
    this.data = precalculate(); 
};

element.onmouseup = function() {
    // 'this' should point to the element being mouse upped
    var data = this.data;
    dosomething(data);
};
  

Ответ №3:

Вы неправильно поняли «глобальная переменная — это зло».

На самом деле, что действительно произошло, так это то, что кто-то захотел быть «частью толпы» и поэтому сказал вам широкое обобщение, когда на самом деле они должны были сказать «используйте глобальные переменные только там, где это уместно».

Что ж, они здесь уместны, мой друг.

Комментарии:

1. Все широкие обобщения — зло! ;o)

Ответ №4:

jQuery делает это возможным с помощью функции .data():

http://api.jquery.com/jQuery.data/

Комментарии:

1. Нет никаких указаний на то, что здесь используется jQuery.

2. @user: Просто то, что не имеет смысла загружать целую библиотеку ради единственной потребности, которая легко решается в самом языке.

3. Я думаю, что это верный аргумент. Если решение не является хорошим, не голосуйте за него. Но пользователь специально не сказал «нет jquery».

4. @user: Да, и я не голосовал ни за, ни против. Просто подумал, что это стоит прокомментировать. jQuery может быть отличным решением, но не всегда.

5. Согласен, и для протокола, я проголосовал за ваше решение, и если бы я знал это, я бы предложил его вместо этого, но я придерживаюсь того, что знаю, пока не узнаю лучше.

Ответ №5:

Вам может сойти с рук использование глобальных переменных, если вы сведете их к минимуму, например, вы можете размещать данные в одном глобальном пространстве имен:

 App = {};

element.onmousedown = function() {
   App.data = "hello";
}

element.onmouseup = function() {
   console.log(App.data);
}
  

Ответ №6:

Другим, более общим решением является создание функций, которые кэшируют свои результаты, используя метод, который называется запоминанием. При поиске есть много чего. Следующий код делает именно это :

 Function.prototype.memoize = function() {
    var fn = this;
    this.memory = {};
    return function() {
        var args = Array.prototype.slice.call(arguments);
        return fn.memory[args] ? fn.memory[args] : fn.memory[args] = fn.apply(this, arguments);
    };
};
  

например, у вас есть дорогостоящая функция под названием exfunc..

 newFunc = exfunc.memoize();
  

Приведенная выше инструкция создает новую функцию с именем newFunc, которая кэширует результат исходной функции, так что при первом выполнении фактический код и все последующие вызовы извлекаются из локального кэша.

В основном это работает с функциями, возвращаемое значение которых не зависит от глобального состояния.

Дополнительная информация: http://osteele.com/archives/2006/04/javascript-memoization