return
Оператор return завершает выполнение текущей функции и возвращает её значение.
Интерактивный пример
Синтаксис
return [[выражение]];
Выражение, значение которого будет возвращено. Если не указано, вместо него возвращается undefined .
Описание
При вызове оператора return в функции её выполнение прекращается. Указанное значение возвращается в место вызова функции. Например, приведённая ниже функция возвращает возведённое в квадрат значение своего аргумента, x (где x – это число):
function square(x) return x * x; > var demo = square(3); // значение demo будет равняться 9
Если возвращаемое значение не указано, вместо него возвращается undefined .
Следующие выражения всегда прерывают выполнение функции:
return; return true; return false; return x; return x + y / 3;
Автоматическая расстановка точек с запятыми
На выражение return влияет автоматическая расстановка точек с запятыми (ASI). Разрыв строки не допускается между ключевым словом return и выражением.
return a + b;
трансформируется ASI в:
return; a + b;
В консоли появится предупреждение «unreachable code after return statement».
Примечание: Начиная с Gecko 40, предупреждение в консоли появляется, если обнаружен недостижимый код после return .
Для того, чтобы избежать данной проблемы (предотвратить ASI), можно использовать скобки:
return ( a + b; );
Примеры
Прерывание функции
Функция немедленно останавливается в точке, где вызывается return .
function counter() for (var count = 1; ; count++) // бесконечный цикл console.log(count + "A"); // до 5 if (count === 5) return; > console.log(count + "B"); // до 4 > console.log(count + "C"); // никогда не появляется > counter(); // Выводит: // 1A // 1B // 2A // 2B // 3A // 3B // 4A // 4B // 5A
Возвращение функции
Смотрите также статью о замыканиях.
function magic(x) return function calc(x) return x * 42; >; > var answer = magic(); answer(1337); // 56154
Спецификации
Specification |
---|
ECMAScript Language Specification # sec-return-statement |
Совместимость с браузерами
BCD tables only load in the browser
как вернуть значение из функции js
Чтобы вернуть некое значение из функции используется ключевое слово return . В качестве значения может быть что угодно, в зависимости от цели и задачи для этой функции.
Пример ниже показывает функцию, которая возвращает значения типа boolean . Такие функции называются предикатами.
function isHero(person) return person.name === 'Harry Potter'; > const person = 'Huge Plotter'; isHero(person); // false
Вытащить переменную из функции Javascript
Не получается вытащить значение переменной из функции, всё время выводится ошибка Uncaught ReferenceError: devuuid_raw is not defined Задача такая: нужно вывести значение переменной за пределы функции, т.к далее значение переменной будет посылаться через другую функцию на сервер. Код:
document.addEventListener("deviceready", onDeviceReady, false); function onDeviceReady() < console.log("Device is ready"); var element = document.getElementById('devProps'); devuuid_raw = device.uuid; return devuuid_raw; element.innerHTML = 'Идентификатор устройства: ' + device.uuid + '
'; > var devuuid = devuuid_raw;
Отслеживать
задан 13 апр 2014 в 14:00
red_sensor red_sensor
25 2 2 серебряных знака 7 7 бронзовых знаков
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Вы абсолютно не понимаете, как работает JavaScript. Рекомендую почитать «Книгу с носорогом». Три грубейшие ошибки:
- Код после инструкции return (он не выполнится)
- Объявление переменной без ключевого слова var
- Непонимание того, что на момент выполнения этой строки: var devuuid = devuuid_raw;
onDeviceReady еще не сработал.
Отслеживать
ответ дан 13 апр 2014 в 14:24
2,391 2 2 золотых знака 18 18 серебряных знаков 23 23 бронзовых знака
Спасибо за ответ, return я изначально не ставил, так посоветовали сделать на другом форме, что для меня тоже показалось странным, переменную без var я объявил глобально, в надежде что она будет видна за пределами функции, но увы она не видна. Насчет «onDeviceReady еще не сработал.» не понимаю, а когда он сработает? Нужно ли объявить переменную по-другому?
13 апр 2014 в 14:35
он сработает в функции onDeviceReady() , вы можете вызвать из нее другую. это называется асинхронное выполнение. для понимания медитируйте на вот такой код: var a=0; setTimeout(setA,1000); //одноразовое событие таймера, через 1с function setA() < a=1; >console.log(a); //0
13 апр 2014 в 14:43
Спасибо, это немного проясняет ситуацию. Моя ситуация похожа на ваш пример, но мне как раз нужно чтобы вывелось 1, если исходить из вашего примера
13 апр 2014 в 15:59
так var a=0; setTimeout(setA,1000); //одноразовое событие таймера, через 1с function setA() < a=1; showA(); >function showA() < console.log(a); //1 >
13 апр 2014 в 16:22
подобный вариант пробовал, в том то и дело нужно обойтись без второй функции, а сделать как у вас здесь: var a=0; setTimeout(setA,1000); //одноразовое событие таймера, через 1с function setA() < a=1; >console.log(a); //0 только чтобы в итоге вывелось 1 т.е чтобы в итоге переменная а была по за функцией и была равна 1 (какое значение ей было задано в функции, такое же должно быть в этой переменной и вне функции)
Замыкания, функции изнутри
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Более новая информация по этой теме находится на странице https://learn.javascript.ru/closure.
В этой главе мы продолжим рассматривать, как работают переменные, и, как следствие, познакомимся с замыканиями. От глобального объекта мы переходим к работе внутри функций.
Лексическое окружение
Все переменные внутри функции – это свойства специального внутреннего объекта LexicalEnvironment , который создаётся при её запуске.
Мы будем называть этот объект «лексическое окружение» или просто «объект переменных».
При запуске функция создаёт объект LexicalEnvironment , записывает туда аргументы, функции и переменные. Процесс инициализации выполняется в том же порядке, что и для глобального объекта, который, вообще говоря, является частным случаем лексического окружения.
В отличие от window , объект LexicalEnvironment является внутренним, он скрыт от прямого доступа.
Пример
Посмотрим пример, чтобы лучше понимать, как это работает:
function sayHi(name) < var phrase = "Привет, " + name; alert( phrase ); >sayHi('Вася');
При вызове функции:
-
До выполнения первой строчки её кода, на стадии инициализации, интерпретатор создаёт пустой объект LexicalEnvironment и заполняет его. В данном случае туда попадает аргумент name и единственная переменная phrase :
function sayHi(name) < // LexicalEnvironment = < name: 'Вася', phrase: undefined >var phrase = "Привет, " + name; alert( phrase ); > sayHi('Вася');
function sayHi(name) < // LexicalEnvironment = < name: 'Вася', phrase: undefined >var phrase = "Привет, " + name; // LexicalEnvironment = < name: 'Вася', phrase: 'Привет, Вася'>alert( phrase ); > sayHi('Вася');
Тонкости спецификации
Если почитать спецификацию ECMA-262, то мы увидим, что речь идёт о двух объектах: VariableEnvironment и LexicalEnvironment .
Но там же замечено, что в реализациях эти два объекта могут быть объединены. Так что мы избегаем лишних деталей и используем везде термин LexicalEnvironment , это достаточно точно позволяет описать происходящее.
Более формальное описание находится в спецификации ECMA-262, секции 10.2-10.5 и 13.
Доступ ко внешним переменным
Из функции мы можем обратиться не только к локальной переменной, но и к внешней:
var userName = "Вася"; function sayHi() < alert( userName ); // "Вася" >
Интерпретатор, при доступе к переменной, сначала пытается найти переменную в текущем LexicalEnvironment , а затем, если её нет – ищет во внешнем объекте переменных. В данном случае им является window .
Такой порядок поиска возможен благодаря тому, что ссылка на внешний объект переменных хранится в специальном внутреннем свойстве функции, которое называется [[Scope]] . Это свойство закрыто от прямого доступа, но знание о нём очень важно для понимания того, как работает JavaScript.
При создании функция получает скрытое свойство [[Scope]] , которое ссылается на лексическое окружение, в котором она была создана.
В примере выше таким окружением является window , так что создаётся свойство:
sayHi.[[Scope]] = window
Это свойство никогда не меняется. Оно всюду следует за функцией, привязывая её, таким образом, к месту своего рождения.
При запуске функции её объект переменных LexicalEnvironment получает ссылку на «внешнее лексическое окружение» со значением из [[Scope]] .
Если переменная не найдена в функции – она будет искаться снаружи.
Именно благодаря этой механике в примере выше alert(userName) выводит внешнюю переменную. На уровне кода это выглядит как поиск во внешней области видимости, вне функции.
- Каждая функция при создании получает ссылку [[Scope]] на объект с переменными, в контексте которого была создана.
- При запуске функции создаётся новый объект с переменными LexicalEnvironment . Он получает ссылку на внешний объект переменных из [[Scope]] .
- При поиске переменных он осуществляется сначала в текущем объекте переменных, а потом – по этой ссылке.
Выглядит настолько просто, что непонятно – зачем вообще говорить об этом [[Scope]] , об объектах переменных. Сказали бы: «Функция читает переменные снаружи» – и всё. Но знание этих деталей позволит нам легко объяснить и понять более сложные ситуации, с которыми мы столкнёмся далее.
Всегда текущее значение
Значение переменной из внешней области берётся всегда текущее. Оно может быть уже не то, что было на момент создания функции.
Например, в коде ниже функция sayHi берёт phrase из внешней области:
var phrase = 'Привет'; function sayHi(name) < alert(phrase + ', ' + name); >sayHi('Вася'); // Привет, Вася (*) phrase = 'Пока'; sayHi('Вася'); // Пока, Вася (**)
На момент первого запуска (*) , переменная phrase имела значение ‘Привет’ , а ко второму (**) изменила его на ‘Пока’ .
Это естественно, ведь для доступа к внешней переменной функция по ссылке [[Scope]] обращается во внешний объект переменных и берёт то значение, которое там есть на момент обращения.
Вложенные функции
Внутри функции можно объявлять не только локальные переменные, но и другие функции.
К примеру, вложенная функция может помочь лучше организовать код:
function sayHiBye(firstName, lastName) < alert( "Привет, " + getFullName() ); alert( "Пока, " + getFullName() ); function getFullName() < return firstName + " " + lastName; >> sayHiBye("Вася", "Пупкин"); // Привет, Вася Пупкин ; Пока, Вася Пупкин
Здесь, для удобства, создана вспомогательная функция getFullName() .
Вложенные функции получают [[Scope]] так же, как и глобальные. В нашем случае:
getFullName.[[Scope]] = объект переменных текущего запуска sayHiBye
Благодаря этому getFullName() получает снаружи firstName и lastName .
Заметим, что если переменная не найдена во внешнем объекте переменных, то она ищется в ещё более внешнем (через [[Scope]] внешней функции), то есть, такой пример тоже будет работать:
var phrase = 'Привет'; function say() < function go() < alert( phrase ); // найдёт переменную снаружи >go(); > say();
Возврат функции
Рассмотрим более «продвинутый» вариант, при котором внутри одной функции создаётся другая и возвращается в качестве результата.
В разработке интерфейсов это совершенно стандартный приём, функция затем может назначаться как обработчик действий посетителя.
Здесь мы будем создавать функцию-счётчик, которая считает свои вызовы и возвращает их текущее число.
В примере ниже makeCounter создаёт такую функцию:
function makeCounter() < var currentCount = 1; return function() < // (**) return currentCount++; >; > var counter = makeCounter(); // (*) // каждый вызов увеличивает счётчик и возвращает результат alert( counter() ); // 1 alert( counter() ); // 2 alert( counter() ); // 3 // создать другой счётчик, он будет независим от первого var counter2 = makeCounter(); alert( counter2() ); // 1
Как видно, мы получили два независимых счётчика counter и counter2 , каждый из которых незаметным снаружи образом сохраняет текущее количество вызовов.
Где? Конечно, во внешней переменной currentCount , которая у каждого счётчика своя.
Если подробнее описать происходящее:
-
В строке (*) запускается makeCounter() . При этом создаётся LexicalEnvironment для переменных текущего вызова. В функции есть одна переменная var currentCount , которая станет свойством этого объекта. Она изначально инициализуется в undefined , затем, в процессе выполнения, получит значение 1 :
function makeCounter() < // LexicalEnvironment = < currentCount: undefined >var currentCount = 1; // LexicalEnvironment = < currentCount: 1 >return function() < // [[Scope]] ->LexicalEnvironment (**) return currentCount++; >; > var counter = makeCounter(); // (*)
На этом создание «счётчика» завершено.
Итоговым значением, записанным в переменную counter , является функция:
function() < // [[Scope]] -> return currentCount++; >;
Возвращённая из makeCounter() функция counter помнит (через [[Scope]] ) о том, в каком окружении была создана.
Это и используется для хранения текущего значения счётчика.
Далее, когда-нибудь, функция counter будет вызвана. Мы не знаем, когда это произойдёт. Может быть, прямо сейчас, но, вообще говоря, совсем не факт.
Эта функция состоит из одной строки: return currentCount++ , ни переменных ни параметров в ней нет, поэтому её собственный объект переменных, для краткости назовём его LE – будет пуст.
Однако, у неё есть свойство [[Scope]] , которое указывает на внешнее окружение. Чтобы увеличить и вернуть currentCount , интерпретатор ищет в текущем объекте переменных LE , не находит, затем идёт во внешний объект, там находит, изменяет и возвращает новое значение:
function makeCounter() < var currentCount = 1; return function() < return currentCount++; >; > var counter = makeCounter(); // [[Scope]] -> alert( counter() ); // 1, [[Scope]] -> alert( counter() ); // 2, [[Scope]] -> alert( counter() ); // 3, [[Scope]] ->
Переменную во внешней области видимости можно не только читать, но и изменять.
В примере выше было создано несколько счётчиков. Все они взаимно независимы:
var counter = makeCounter(); var counter2 = makeCounter(); alert( counter() ); // 1 alert( counter() ); // 2 alert( counter() ); // 3 alert( counter2() ); // 1, счётчики независимы
Они независимы, потому что при каждом запуске makeCounter создаётся свой объект переменных LexicalEnvironment , со своим свойством currentCount , на который новый счётчик получит ссылку [[Scope]] .
Свойства функции
Функция в JavaScript является объектом, поэтому можно присваивать свойства прямо к ней, вот так:
function f() <> f.test = 5; alert( f.test );
Свойства функции не стоит путать с переменными и параметрами. Они совершенно никак не связаны. Переменные доступны только внутри функции, они создаются в процессе её выполнения. Это – использование функции «как функции».
А свойство у функции – доступно отовсюду и всегда. Это – использование функции «как объекта».
Если хочется привязать значение к функции, то можно им воспользоваться вместо внешних переменных.
В качестве демонстрации, перепишем пример со счётчиком:
function makeCounter() < function counter() < return counter.currentCount++; >; counter.currentCount = 1; return counter; > var counter = makeCounter(); alert( counter() ); // 1 alert( counter() ); // 2
При запуске пример работает также.
Принципиальная разница – во внутренней механике и в том, что свойство функции, в отличие от переменной из замыкания – общедоступно, к нему имеет доступ любой, у кого есть объект функции.
Например, можно взять и поменять счётчик из внешнего кода:
var counter = makeCounter(); alert( counter() ); // 1 counter.currentCount = 5; alert( counter() ); // 5
Статические переменные
Иногда свойства, привязанные к функции, называют «статическими переменными».
В некоторых языках программирования можно объявлять переменную, которая сохраняет значение между вызовами функции. В JavaScript ближайший аналог – такое вот свойство функции.
Итого: замыкания
Замыкание – это функция вместе со всеми внешними переменными, которые ей доступны.
Таково стандартное определение, которое есть в Wikipedia и большинстве серьёзных источников по программированию. То есть, замыкание – это функция + внешние переменные.
Тем не менее, в JavaScript есть небольшая терминологическая особенность.
Обычно, говоря «замыкание функции», подразумевают не саму эту функцию, а именно внешние переменные.
Иногда говорят «переменная берётся из замыкания». Это означает – из внешнего объекта переменных.
Что это такое – «понимать замыкания?»
Иногда говорят «Вася молодец, понимает замыкания!». Что это такое – «понимать замыкания», какой смысл обычно вкладывают в эти слова?
«Понимать замыкания» в JavaScript означает понимать следующие вещи:
- Все переменные и параметры функций являются свойствами объекта переменных LexicalEnvironment . Каждый запуск функции создаёт новый такой объект. На верхнем уровне им является «глобальный объект», в браузере – window .
- При создании функция получает системное свойство [[Scope]] , которое ссылается на LexicalEnvironment , в котором она была создана.
- При вызове функции, куда бы её ни передали в коде – она будет искать переменные сначала у себя, а затем во внешних LexicalEnvironment с места своего «рождения».
В следующих главах мы углубим это понимание дополнительными примерами, а также рассмотрим, что происходит с памятью.