2011-12-23 2 views
13

Во многих браузерах, которые я тестировал, блоки JavaScript фактически возвращают значение. Вы можете проверить его на любой консоли:Использование возвращаемого значения блока в JavaScript

for(var i = 0; i < 10; i++) { 
    var sqrt = Math.sqrt(i); 
    if(Math.floor(sqrt) === sqrt) { 
     i; 
    } 
} 

Значение «return» - это последнее квадратное число, то есть 9! Но поскольку это не выражение, я полагаю, вы не можете этого сделать:

for(var i = 0; i < 10; i++) { 
    ... 
} + 5 

Это не работает. Это дает + 5, или 5, конечно, потому что это отдельное заявление. Помещение цикла в круглые скобки, очевидно, не выполняется, и если блок находится в круглых скобках (например, ({f(); r}) - не работает), он рассматривается как объект и выдает синтаксическую ошибку.

Один из способов, чтобы воспользоваться возвращаемым значением, как таковой, заключается в использовании eval:

eval('for(var i = 0; i < 10; i++) {var sqrt = Math.sqrt(i);if(Math.floor(sqrt) === sqrt) {i;}}') + 5; // 14 

Но я явно не буду хотеть использовать, что если eval является единственным решением. Есть ли способ использовать результирующее значение блока, не используя eval, что мне не хватает? Мне очень нравится эта функция :)

+4

Блоки заявления, а не выражения. Поэтому вы не можете использовать их в качестве операндов (вы не можете использовать на них операторы) ... –

+0

@ ŠimeVidas: Точно - есть способ как-то заставить их работать? Не использовать 'eval'? – Ryan

+1

Вы должны рассматривать возвращаемое значение eval как аномалию, а не ограничение, которое JS «обычно» (чтение: игнорирование вне 'eval') накладывается. Блоки ** не ** выражения. – delnan

ответ

14

В JavaScript операторы возвращают значения типа завершения (который не является типом языка, а специфицированным типом).

Тип Завершение используется для объяснения поведения операторов (break, continue, return и throw), которые выполняют нелокальные передачу контроля. Значения типа Completion представляют из себя триплеты вида (типа, значения, целевого), где типа является одним из нормальных, разрыв, продолжают, возвращения, или бросок, значение любое значение языка ECMAScript или пустой и цель - любой идентификатор ECMAScript или пустой.

Источник: http://es5.github.com/x8.html#x8.9

Таким образом, eval() оценивает программу, которая была передана в качестве исходного текста. Эта программа (например, любая программа JavaScript) возвращает значение Completion. Второй элемент в этом значении Completion (элемент «value») возвращается вызовом eval().

Итак, с eval вы можете получить значение завершения программы JavaScript. Мне не известно о каком-либо другом методе для этого ...

+0

Я бы пообещал, что этот материал типа завершения - это просто указание некоторой оригинальной реализации 'eval'. – hugomg

+1

@missingno Я могу заверить вас, что тип завершения является неотъемлемой частью языка. Значения завершения используются интерпретатором для определения следующего этапа выполнения (т. Е. Управления передачей функции вызывающего абонента, перехода к началу итерации и т. Д.). –

+1

Извините, за путаницу. Я не могу придумать ни одного случая другого, кроме eval, который заботится о значении * завершения *. (Второе значение в этой тройке, и то, что имеет значение для этого конкретного вопроса) – hugomg

2

В ES7 есть предложение ввести do expression, который позволяет любому блоку превращаться в выражение. Выражение do вычисляет блок и возвращает его значение завершения.

Используя этот синтаксис, который вы можете попробовать сегодня с Вавилонской использованием syntax-do-expression и transform-do-expression плагинов, ваш пример будет выглядеть следующим образом:

function lastSquareNumber(val) { 
    return do { for(var i = 0; i < val; i++) { 
     var sqrt = Math.sqrt(i); 
     if(Math.floor(sqrt) === sqrt) { 
      i; 
     } 
    }} 
} 

console.log(lastSquareNumber(10)); 
+0

Прохладный! Я как-то сомневаюсь, что это будет сделано, но все равно хорошо видно. – Ryan

+0

Это выглядит очень аккуратно, я надеюсь, что это будет реализовано в ES7, и нам придется ждать этого для другого, пока я думаю :) – SidOfc