Почему компилятор закрытия не сокращает это?

#javascript #minify #google-closure-compiler

#javascript #минимизировать #google-closure-compiler

Вопрос:

Я не уверен, является ли это просто ошибкой или предполагаемой функцией.

В принципе, у меня есть эта крошечная функция (теперь я вижу, что end здесь окрашена в синий цвет, но это работает просто отлично, если я переименую ее во что-то другое, у меня все еще будет проблема):

 function f(a, b) {
    var start = Math.min(a, b);
    var end = Math.max(a, b);

    tb.selectionStart = start;
    tb.selectionEnd = end;
};
  

При компиляции с закрытием я получаю:

 function f(a,b){var c=Math.max(a,b);tb.selectionStart=Math.min(a,b);tb.selectionEnd=c};
  

Однако, почему selectionStart устанавливается в Math.min значение напрямую, в то время как selecitonEnd устанавливается в переменную ( c ), которая объявляется первой? Не проще ли это сделать tb.selectionEnd=Math.max(a,b) ?

Приветствуются любые идеи.

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

1. Просто в качестве дополнительного примечания, подсветка синтаксиса SO — универсальная вещь. Он будет стараться изо всех сил выделить любой язык. Таким образом, он точно не определяет JS, только синтаксис C и выделяет общие ключевые слова. Кроме того, вы можете вывести красиво напечатанную версию вашего кода, что делает его более читаемым, чтобы увидеть, что делает компилятор закрытия.

Ответ №1:

РЕДАКТИРОВАТЬ: ПО ЭТОЙ ССЫЛКЕ ЕСТЬ «ОФИЦИАЛЬНЫЙ» ОТВЕТ: https://web.archive.org/web/20151226143155/http://code.google.com/p/closure-compiler/issues/detail?id=410

Я думаю, что присвоение переменной, за которым немедленно следует использование этой переменной, может быть встроено. Однако, если есть какое-либо промежуточное утверждение, которое не может быть доказано как свободное от побочных эффектов, то компилятор не будет его встроять.

В вашем случае присвоение переменной «start» отделено от использования «start» только оператором присваивания «end». Однако этот оператор не имеет побочных эффектов, поскольку Math.max является внутренней функцией, и компилятор знает, что он не имеет побочных эффектов.

Однако в вашем случае присвоение переменной «end» отделено от использования этой переменной оператором, который является присвоением «start» свойству. Теперь, я полагаю, что компилятор не предполагает, что простое присвоение свойству всегда не имеет побочных эффектов; это потому, что некоторые свойства, будучи назначенными, на самом деле вызывают другое поведение или изменяют глобальное состояние (например, регулярное выражение). В некоторых системах назначения свойств фактически запускают определенные системные функции (например, аппаратный интерфейс), которые, в свою очередь, могут содержать побочные эффекты.

Вот почему иногда, когда у вас есть такой код:

 foo.bar = 1;
foo.bar = 2;
foo.bar = 3;
  

Компилятор не будет удалять первые два оператора, поскольку присвоение «bar» может иметь побочные эффекты.

Итак, в вашем вопросе переменная «end» не может быть встроенной, потому что оператор tb.selectionStart = start; может иметь побочные эффекты (возможно, только в необычных случаях).

Если вы сделаете «tb» локальной переменной или чем-то, над чем компилятор имеет полный контроль (например, простым объектом: var tb = {}; ), то вы обнаружите, что компилятор просто отлично выполняет все назначения.

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

1. Я понимаю, но не мог ли компилятор быть оптимизирован таким образом, Math.max чтобы не создавалось побочных эффектов?

2. Math.max является внутренней функцией JS и не имеет побочных эффектов. Это находится во внешнем файле компилятора. Однако ваше назначение tb.SelectionStart не гарантирует отсутствия побочных эффектов. Присвоение переменной может быть встроено только в том случае, если между присвоением и использованием нет инструкции, которая потенциально может содержать побочные эффекты.

3. О, теперь я понимаю. Не знал о геттерах / установщиках, которые тоже могут что-то делать при использовании.

4. Вы можете доказать это следующим экспериментом: 1) удалите функцию-оболочку, 2) удалите «var» перед «start» и «end» (таким образом, сделав их глобальными переменными), 3) скомпилируйте. Вы обнаружите, что, сюрприз!, компилятор не удаляет ни «start», ни «end». Это потому, что глобальная переменная доступна для всех функций, и пока есть что -то, что потенциально может содержать побочные эффекты, оно может обращаться к этим глобальным переменным! Поэтому компилятор должен оставить их в покое.

5. Подумайте в терминах «tb.SelectionStart», включающего какую-либо функцию аппаратной системы — вы знаете, JS не ограничивается запуском в браузере — и он получает доступ к переменным «start» и «end». Вы поняли идею — побочный эффект. Конечно, это очень неприятный способ написания программ, но компилятор должен быть консервативным и предполагать, что все мы пишем опасный код, чтобы застрелиться.

Ответ №2:

если вы вставляете этот код, это работает.

 function f(a, b) {
    var start = Math.min(a, b);
    tb.selectionStart = start;

    var end = Math.max(a, b);
    tb.selectionEnd = end;
};
  

function f(a,b){tb.selectionStart=Math.min(a,b);tb.selectionEnd=Math.max(a,b)};

i это ошибка компилятора закрытия.

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

1. Я могу воспроизвести это, в то время как мой или ваш заказ не должен иметь никакого значения. Ну, я думаю, с этим ничего не поделаешь.

2. я отправил этот раздел на страницу проекта компилятора закрытия. надеюсь, это будет исправлено. code.google.com/p/closure-compiler/issues/detail?id=410

3. Большое спасибо. Здорово, что вы это сделали.

4. Я думаю, что это вопрос побочных эффектов — смотрите Мой ответ.