Страницы

Поиск по вопросам

Показаны сообщения с ярлыком scope. Показать все сообщения
Показаны сообщения с ярлыком scope. Показать все сообщения

понедельник, 16 декабря 2019 г.

Область видимости исключения в блоке catch

#javascript #переменные #scope #javascript_faq


Собственно, почему не функция, а только сам блок?

Проверено в Хроме, FF, IE11 и Опере 12.



function test() {
  var e = 10, x = 5;

  try {
    console.log(e, x); // 10 5
    throw 15;
  } catch (e) {
    var x;
    console.log(e, x); // 15 5
    e = x = 17;
    console.log(e, x); // 17 17
  } finally {
    console.log(e, x); // 10 17
  }
}

test();




Ну и ES6-версия с декомпозицией:



function test() {
  var e = 10, x = 5;

  try {
    console.log(e, x); // 10 5
    throw {e: 15, x:3};
  } catch ({e, x}) {
    console.log(e, x); // 15 3
    e = x = 17;
    console.log(e, x); // 17 17
  } finally {
    console.log(e, x); // 10 5
  }
}

test();



    


Ответы

Ответ 1



Обратимся к спецификации: Catch : catch ( CatchParameter ) Block в oldEnv сохраняется LexicalEnvironment из текущего контекста создается catchEnv как NewDeclarativeEnvironment(oldEnv). для каждого имени аргумента из BoundNames в CatchParameter в catchEnv создается MutableBinding текущим LexicalEnvironment в контексте устанавливается catchEnv в status сохраняется результат BindingInitialization если status не нормальный текущим LexicalEnvironment в контексте устанавливается oldEnv значением catch блока устанавливается значение status В B сохраняется результат выполнения Block. текущим LexicalEnvironment в контексте устанавливается oldEnv значением catch блока устанавливается значение B Что можно отметить в данном алгоритме? при входе в catch создается новый LexicalEnvironment значения указанные в параметрах catch связываются с новым LexicalEnvironment при выходе - всегда восстанавливается старый LexicalEnvironment Таким образом e объявленную выше var e=10 перекрывает e в выражении catch (e), значение которой и используется внутри блока. И так как при выходе из блока восстанавливается старый LexicalEnvironment, внутри блока finally будет видна переменная объявленная через var. Теперь можно перейти к вопросу из комментария: @VladimirGamalian, а разве NewDeclarativeEnvironment не означает собственный скоуп? Но у catch'а ведь его нет? Или это такая магия за счёт всплытия объявлений, что всплывает всё кроме исключения? Как-то странно получается... В контексте выполнения присутствуют два дополнительных свойства LexicalEnvironment - определяет Lexical Environment, в котором хранятся идентификаторы созданные в коде в текущем контексте VariableEnvironment - определяет Lexical Environment, в котором EnvironmentRecord хранит привязки созданные с помощью VariableStatements в текущем контексте При использовании выражения var переменные добавляются в VariableEnvironment текущего контекста. Так как при заходе в catch меняется только LexicalEnvironment - то становится не важно в каком месте переменная объявлена с помощью var - она все равно будет добавлена в VariableEnvironment и будет доступна из любого места в текущем контексте выполнения.

Ответ 2



В блоке catch создается копия объекта созданного оператором throw, finally же имеет доступ к внешнему по отношению к catch объекту, который не менялся. Обновление В catch передается временных безымянный объект созданный throw, поля которого переезжают в глобальный объект и перекрывают переменные e и x, по выходу из catch он уничтожается, поэтому в finally выводится объявленные в начале функции e и x.

суббота, 15 июня 2019 г.

Rails: scope из модели в self

Я получаю фильтр фильмов путем присваивания @movies нового значения, но я хотел бы чтобы возвращало в self и кусок кода @movies = @movies.filter_ratings(params[:ratings]) стал красивым: @movies.filter_ratings(params[:ratings])
Рою гугл 2 день, помогите пожалуйста!
Мой контроллер:
class MoviesController < ApplicationController def index @movies = Movie.sort_by(params[:sort_by]) @movies = @movies.filter_ratings(params[:ratings]) unless (params[:ratings]).nil? end end
Моя модель:
class Movie < ActiveRecord::Base # сортируем по требуемому полю scope :sort_by, ->(sorting) { all.order(sorting) } # выводим список рейтингов scope :all_ratings, -> { all.map{|movie| movie.rating }.uniq } # получаем фильмы согласно фильтру пользователя scope :filter_ratings, ->(filters) { where(:rating => filters.each_key.to_a) } end


Ответ

В ActiveRecord нет методов (публичных как минимум), меняющих уже созданный Relation
Так задумано (см. комментарии к этому коммиту в Rails). API построителя запросов задуман, как иммутабельный, чтобы он был более предсказуемым, не вызывал неожиданного поведения где-то, где это не указано явно.
Но я не вижу ни единой причины, по которой unless (params[:ratings]).nil? нельзя проверять в самом скоупе, возвращая self, если изменения не требуются:
scope :filter_ratings, ->(filters) { if filters.nil? self else where(:rating => filters.each_key.to_a) end }
Тогда сделать описанный вами запрос можно с помощью более длинной цепочки:
@movies = Movie.sort_by(params[:sort_by]).filter_ratings(params[:ratings])
Переносы/отступы по вкусу.

суббота, 27 октября 2018 г.

Область видимости исключения в блоке catch

Собственно, почему не функция, а только сам блок?
Проверено в Хроме, FF, IE11 и Опере 12.
function test() { var e = 10, x = 5; try { console.log(e, x); // 10 5 throw 15; } catch (e) { var x; console.log(e, x); // 15 5 e = x = 17; console.log(e, x); // 17 17 } finally { console.log(e, x); // 10 17 } } test();
Ну и ES6-версия с декомпозицией:
function test() { var e = 10, x = 5; try { console.log(e, x); // 10 5 throw {e: 15, x:3}; } catch ({e, x}) { console.log(e, x); // 15 3 e = x = 17; console.log(e, x); // 17 17 } finally { console.log(e, x); // 10 5 } } test();


Ответ

Обратимся к спецификации
Catch : catch ( CatchParameter ) Block в oldEnv сохраняется LexicalEnvironment из текущего контекста создается catchEnv как NewDeclarativeEnvironment(oldEnv) для каждого имени аргумента из BoundNames в CatchParameter в catchEnv создается MutableBinding текущим LexicalEnvironment в контексте устанавливается catchEnv в status сохраняется результат BindingInitialization если status не нормальный текущим LexicalEnvironment в контексте устанавливается oldEnv значением catch блока устанавливается значение status В B сохраняется результат выполнения Block. текущим LexicalEnvironment в контексте устанавливается oldEnv значением catch блока устанавливается значение B
Что можно отметить в данном алгоритме?
при входе в catch создается новый LexicalEnvironment значения указанные в параметрах catch связываются с новым LexicalEnvironment при выходе - всегда восстанавливается старый LexicalEnvironment
Таким образом e объявленную выше var e=10 перекрывает e в выражении catch (e), значение которой и используется внутри блока.
И так как при выходе из блока восстанавливается старый LexicalEnvironment, внутри блока finally будет видна переменная объявленная через var.
Теперь можно перейти к вопросу из комментария:
@VladimirGamalian, а разве NewDeclarativeEnvironment не означает собственный скоуп? Но у catch'а ведь его нет? Или это такая магия за счёт всплытия объявлений, что всплывает всё кроме исключения? Как-то странно получается...
В контексте выполнения присутствуют два дополнительных свойства
LexicalEnvironment - определяет Lexical Environment, в котором хранятся идентификаторы созданные в коде в текущем контексте VariableEnvironment - определяет Lexical Environment, в котором EnvironmentRecord хранит привязки созданные с помощью VariableStatements в текущем контексте
При использовании выражения var переменные добавляются в VariableEnvironment текущего контекста. Так как при заходе в catch меняется только LexicalEnvironment - то становится не важно в каком месте переменная объявлена с помощью var - она все равно будет добавлена в VariableEnvironment и будет доступна из любого места в текущем контексте выполнения.