Как вернуть объект из функции js
Перейти к содержимому

Как вернуть объект из функции js

  • автор:

Как функцией в JS возвратить массив (объект)?

eca28a6df3494898a52a44f25dbbd7a5.jpg

Как функцией в JS возвратить массив (объект)?
Пробую возвратить — не получается. Вот код:

$(document).ready( function() < console.log(getStreets('Вовчинець') ); >); function getStreets(city) < $.post( 'export/getStreets.php', < misto_selo_key: city >) .done( function( data ) < var availableTags = data.split(","); var availableTagsArr = []; availableTags.forEach(function (street_name) < parts = street_name.split("&"); availableTagsArr.push(); >); console.log(availableTagsArr); return availableTagsArr; >); >
  • Вопрос задан более трёх лет назад
  • 7872 просмотра

Комментировать
Решения вопроса 2

tratotui

Что вы собственно ждете, когда функция getStreets ничего не возвращает — это раз. А второй момент — это то, что загрузка данных может наступить после события ready

Ответ написан более трёх лет назад
Комментировать
Нравится Комментировать
dilistinc @dilistinc Автор вопроса

Ребята, не в асинхронности дело, а в том что return срабатывает для $.post метода ( спасибо тебе tratotui), а не для getStreets(city), так как он находиться внутри метода.
Я поборол эту проблему следующим путем: перед $.post методом создал массив пустой, после неасинхронного запроса возвращаю массив внутри функции getStreets. Собственно всё. Очень благодарен за помощь!

Ответ написан более трёх лет назад
Комментировать
Нравится Комментировать
Ответы на вопрос 4
SPA web-developer
М.Б. async=false?
Ответ написан более трёх лет назад
Комментировать
Нравится 1 Комментировать
нужно листать поэлементно, есть готовые примеры кода (я гуглил var_dump для js 🙂
Ответ написан более трёх лет назад
dilistinc @dilistinc Автор вопроса
Нет! Пробовал.

pavel_salauyou

Павел Соловьёв @pavel_salauyou
Symfony2 & Angular разработчик

никак это ajax, как вариант можно передавать callback функцию, например,

getStreets('Вовчинець', function(response) < console.log(response); >) а в методе done вызывать её function getStreets(city, callback) < // . .done( function( data ) < // . callback(availableTagsArr); >

Ответ написан более трёх лет назад
Комментировать
Нравится Комментировать

TekVanDo

Javascript Developer

$.post — асинхронный метод — и данные в колбэк done приходят позже чем срабатывает console.log (первый), т.ч. в данном конкретно примере вернуть нельзя. Слушайте событие или используйте промисы.

Ответ написан более трёх лет назад
Комментировать
Нравится Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

javascript

  • JavaScript
  • +1 ещё

Выгрузка JS кода в php, но не просто?

  • 1 подписчик
  • 7 часов назад
  • 60 просмотров

Объект функции, NFE

Как мы уже знаем, в JavaScript функция – это значение.

Каждое значение в JavaScript имеет свой тип. А функция – это какой тип?

В JavaScript функции – это объекты.

Можно представить функцию как «объект, который может делать какое-то действие». Функции можно не только вызывать, но и использовать их как обычные объекты: добавлять/удалять свойства, передавать их по ссылке и т.д.

Свойство «name»

Объект функции содержит несколько полезных свойств.

Например, имя функции нам доступно как свойство «name»:

function sayHi() < alert("Hi"); >alert(sayHi.name); // sayHi

Что довольно забавно, логика назначения name весьма умная. Она присваивает корректное имя даже в случае, когда функция создаётся без имени и тут же присваивается, вот так:

let sayHi = function() < alert("Hi"); >; alert(sayHi.name); // sayHi (есть имя!)

Это работает даже в случае присваивания значения по умолчанию:

function f(sayHi = function() <>) < alert(sayHi.name); // sayHi (работает!) >f();

В спецификации это называется «контекстное имя»: если функция не имеет name, то JavaScript пытается определить его из контекста.

Также имена имеют и методы объекта:

let user = < sayHi() < // . >, sayBye: function() < // . >> alert(user.sayHi.name); // sayHi alert(user.sayBye.name); // sayBye

В этом нет никакой магии. Бывает, что корректное имя определить невозможно. В таких случаях свойство name имеет пустое значение. Например:

// функция объявлена внутри массива let arr = [function() <>]; alert( arr[0].name ); // // здесь отсутствует возможность определить имя, поэтому его нет

Впрочем, на практике такое бывает редко, обычно функции имеют name .

Свойство «length»

Ещё одно встроенное свойство «length» содержит количество параметров функции в её объявлении. Например:

function f1(a) <> function f2(a, b) <> function many(a, b, . more) <> alert(f1.length); // 1 alert(f2.length); // 2 alert(many.length); // 2

Как мы видим, троеточие, обозначающее «остаточные параметры», здесь как бы «не считается»

Свойство length иногда используется для интроспекций в функциях, которые работают с другими функциями.

Например, в коде ниже функция ask принимает в качестве параметров вопрос question и произвольное количество функций-обработчиков ответа handler .

Когда пользователь отвечает на вопрос, функция вызывает обработчики. Мы можем передать два типа обработчиков:

  • Функцию без аргументов, которая будет вызываться только в случае положительного ответа.
  • Функцию с аргументами, которая будет вызываться в обоих случаях и возвращать ответ.

Чтобы вызвать обработчик handler правильно, будем проверять свойство handler.length .

Идея состоит в том, чтобы иметь простой синтаксис обработчика без аргументов для положительных ответов (наиболее распространённый случай), но также и возможность передавать универсальные обработчики:

function ask(question, . handlers) < let isYes = confirm(question); for(let handler of handlers) < if (handler.length == 0) < if (isYes) handler(); >else < handler(isYes); >> > // для положительных ответов вызываются оба типа обработчиков // для отрицательных - только второго типа ask("Вопрос?", () => alert('Вы ответили да'), result => alert(result));

Это частный случай так называемого Ad-hoc-полиморфизма – обработка аргументов в зависимости от их типа или, как в нашем случае – от значения length . Эта идея имеет применение в библиотеках JavaScript.

Пользовательские свойства

Мы также можем добавить свои собственные свойства.

Давайте добавим свойство counter для отслеживания общего количества вызовов:

function sayHi() < alert("Hi"); // давайте посчитаем, сколько вызовов мы сделали sayHi.counter++; >sayHi.counter = 0; // начальное значение sayHi(); // Hi sayHi(); // Hi alert( `Вызвана $ раза` ); // Вызвана 2 раза

Свойство не есть переменная

Свойство функции, назначенное как sayHi.counter = 0 , не объявляет локальную переменную counter внутри неё. Другими словами, свойство counter и переменная let counter – это две независимые вещи.

Мы можем использовать функцию как объект, хранить в ней свойства, но они никак не влияют на её выполнение. Переменные – это не свойства функции и наоборот. Это два параллельных мира.

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

function makeCounter() < // вместо // let count = 0 function counter() < return counter.count++; >; counter.count = 0; return counter; > let counter = makeCounter(); alert( counter() ); // 0 alert( counter() ); // 1

Свойство count теперь хранится прямо в функции, а не в её внешнем лексическом окружении.

Это хуже или лучше, чем использовать замыкание?

Основное отличие в том, что если значение count живёт во внешней переменной, то оно не доступно для внешнего кода. Изменить его могут только вложенные функции. А если оно присвоено как свойство функции, то мы можем его получить:

function makeCounter() < function counter() < return counter.count++; >; counter.count = 0; return counter; > let counter = makeCounter(); counter.count = 10; alert( counter() ); // 10

Поэтому выбор реализации зависит от наших целей.

Named Function Expression

Named Function Expression или NFE – это термин для Function Expression, у которого есть имя.

Например, давайте объявим Function Expression:

let sayHi = function(who) < alert(`Hello, $`); >;

И присвоим ему имя:

let sayHi = function func(who) < alert(`Hello, $`); >;

Чего мы здесь достигли? Какова цель этого дополнительного имени func ?

Для начала заметим, что функция всё ещё задана как Function Expression. Добавление «func» после function не превращает объявление в Function Declaration, потому что оно все ещё является частью выражения присваивания.

Добавление такого имени ничего не ломает.

Функция все ещё доступна как sayHi() :

let sayHi = function func(who) < alert(`Hello, $`); >; sayHi("John"); // Hello, John

Есть две важные особенности имени func , ради которого оно даётся:

  1. Оно позволяет функции ссылаться на себя же.
  2. Оно не доступно за пределами функции.

Например, ниже функция sayHi вызывает себя с «Guest» , если не передан параметр who :

let sayHi = function func(who) < if (who) < alert(`Hello, $`); > else < func("Guest"); // использует func, чтобы снова вызвать себя же >>; sayHi(); // Hello, Guest // А вот так - не cработает: func(); // Ошибка, func не определена (недоступна вне функции)

Почему мы используем func ? Почему просто не использовать sayHi для вложенного вызова?

Вообще, обычно мы можем так поступить:

let sayHi = function(who) < if (who) < alert(`Hello, $`); > else < sayHi("Guest"); >>;

Однако, у этого кода есть проблема, которая заключается в том, что значение sayHi может быть изменено. Функция может быть присвоена другой переменной, и тогда код начнёт выдавать ошибки:

let sayHi = function(who) < if (who) < alert(`Hello, $`); > else < sayHi("Guest"); // Ошибка: sayHi не является функцией >>; let welcome = sayHi; sayHi = null; welcome(); // Ошибка, вложенный вызов sayHi больше не работает!

Так происходит, потому что функция берёт sayHi из внешнего лексического окружения. Так как локальная переменная sayHi отсутствует, используется внешняя. И на момент вызова эта внешняя sayHi равна null .

Необязательное имя, которое можно вставить в Function Expression, как раз и призвано решать такого рода проблемы.

Давайте используем его, чтобы исправить наш код:

let sayHi = function func(who) < if (who) < alert(`Hello, $`); > else < func("Guest"); // Теперь всё в порядке >>; let welcome = sayHi; sayHi = null; welcome(); // Hello, Guest (вложенный вызов работает)

Теперь всё работает, потому что имя «func» локальное и находится внутри функции. Теперь оно взято не снаружи (и недоступно оттуда). Спецификация гарантирует, что оно всегда будет ссылаться на текущую функцию.

Внешний код все ещё содержит переменные sayHi и welcome , но теперь func – это «внутреннее имя функции», таким образом она может вызвать себя изнутри.

Это не работает с Function Declaration

Трюк с «внутренним» именем, описанный выше, работает только для Function Expression и не работает для Function Declaration. Для Function Declaration синтаксис не предусматривает возможность объявить дополнительное «внутреннее» имя.

Зачастую, когда нам нужно надёжное «внутреннее» имя, стоит переписать Function Declaration на Named Function Expression.

Итого

Функции – это объекты.

  • name – имя функции. Обычно берётся из объявления функции, но если там нет – JavaScript пытается понять его из контекста.
  • length – количество аргументов в объявлении функции. Троеточие («остаточные параметры») не считается.

Если функция объявлена как Function Expression (вне основного потока кода) и имеет имя, тогда это называется Named Function Expression (Именованным Функциональным Выражением). Это имя может быть использовано для ссылки на себя же, для рекурсивных вызовов и т.п.

Также функции могут содержать дополнительные свойства. Многие известные JavaScript-библиотеки искусно используют эту возможность.

Они создают «основную» функцию и добавляют множество «вспомогательных» функций внутрь первой. Например, библиотека jQuery создаёт функцию с именем $ . Библиотека lodash создаёт функцию _ , а потом добавляет в неё _.clone , _.keyBy и другие свойства (чтобы узнать о ней побольше см. документацию). Они делают это, чтобы уменьшить засорение глобального пространства имён посредством того, что одна библиотека предоставляет только одну глобальную переменную, уменьшая вероятность конфликта имён.

Таким образом, функция может не только делать что-то сама по себе, но также и предоставлять полезную функциональность через свои свойства.

Задачи

Установка и уменьшение значения счётчика

важность: 5

Измените код makeCounter() так, чтобы счётчик мог уменьшать и устанавливать значение:

  • counter() должен возвращать следующее значение (как и раньше).
  • counter.set(value) должен устанавливать счётчику значение value .
  • counter.decrease() должен уменьшать значение счётчика на 1.

Посмотрите код из песочницы с полным примером использования.

P.S. Для того, чтобы сохранить текущее значение счётчика, можно воспользоваться как замыканием, так и свойством функции. Или сделать два варианта решения: и так, и так.

В решении использована локальная переменная count , а методы сложения записаны прямо в counter . Они разделяют одно и то же лексическое окружение и также имеют доступ к текущей переменной count .

function makeCounter() < let count = 0; function counter() < return count++; >counter.set = value => count = value; counter.decrease = () => count--; return counter; >

Стрелочные функции

ES6 представил нам стрелочные функции, которые имеют три основных преимущества. Во-первых, они имеют краткий синтаксис. Во-вторых, они имеют неявный возврат, что позволяет нам писать однострочные выражения.

В-третьих, они не перепривязывают значение this , когда ты используешь стрелочную функцию внутри другой функции, например: обработчики кликов.

Например: у меня есть массив имен const names = [‘Alex’, ‘Julia’]; . Я хочу добавить is cool в конце двух имен.

const newNames = names.map(function (name)  return `$name> is cool`; >); console.log(newNames); // "Alex is cool", "Julia is cool"

Но это не стрелочная функция, так что давай посмотрим, как мы можем это переписать.

Превращение в стрелочную функцию

Первое, что ты делаешь это удаляешь слово function и добавляешь то, что называется жирной стрелкой. Это выглядит так: =>

const newNames = names.map((name) =>  return `$name> is cool`; >); console.log(newNames); // "Alex is cool", "Julia is cool"

Удаление скобок с одиночным параметром

Если у тебя есть только один параметр, ты можешь убрать скобки:

const newNames = names.map((name) =>  return `$name> is cool`; >); console.log(newNames); // "Alex ic cool", "Julia ic cool"

Это своего рода стилистический выбор. Некоторые предпочитают скобки независимо от того, сколько у тебя параметров.

Неявный возврат стрелочных функций

Что такое неявный возврат или implicit return? Давай для начала разберем, что такое явный возврат или explicit return.

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

Итак, если единственная цель стрелочной функции — вернуть что-то, то нет необходимости в слове return .

Наша трехстрочная функция с явным возвратом, теперь является однострочной функцией с неявным возвратом.

const newNames = names.map((name) => `$name> is cool`); console.log(newNames); // "Alex is cool", "Julia is cool"

Мы сделали три вещи здесь:

  • удалили return ;
  • перенесли всё на одну строчку;
  • удалили фигурные скобки.

Когда ты удаляешь фигурные скобки, это будет неявный возврат, который означает, что не нужно указывать return, что мы возвращаем $ is cool .

Стрелочные функции без аргументов

Если у тебя нет аргументов вообще — в приведенных выше примерах, очевидно, нам нужен аргумент — но если аргументов нет вообще, тебе нужно передать пустые скобки.

Сейчас мы просто вернем Alex is cool .

const newNames = names.map(() => `Alex is cool`); console.log(newNames); // "Alex is cool", "Alex is cool"

Есть несколько нюансов в расширенном синтаксисе, которые полезно знать.

Во-первых, если ты пытаешься использовать однострочный синтаксис с одним выражением, а возвращаемое значение является литералом объекта. Можно подумать, что это будет выглядеть так:

(name, age) =>  name: name, age: age >;

Но есть одна загвоздка, которая состоит в том, что этот синтаксис неоднозначен — и будет похоже, что ты пытаешься создать традиционное тело функции.

Чтобы указать, что вместо этого ты хочешь вернуть объект, необходимо обернуть его в скобки:

(name, age) => ( name: name, age: age >);

Область контекста выполнения

В отличие от любой другой формы функции, стрелочные функции не имеют своего собственного контекста выполнения.

Контекст выполнения — это абстрактное понятие среды, в которой Javascript код оценивается и выполняется. Всякий раз, когда какой-либо код выполняется в JavaScript, он запускается в контексте выполнения.

Это означает, что this и аргументы наследуются от их родительской функции.

Например, сравним обычную функцию со стрелочной:

const test =  name: "test object", createAnonFunction: function ()  return function ()  console.log(this.name); console.log(arguments); >; >, createArrowFunction: function ()  return () =>  console.log(this.name); console.log(arguments); >; >, >;

У нас есть простой объект test с двумя методами, каждый из которых представляет собой функцию, которая создает и возвращает анонимную функцию.

Разница в том, что в первом случае используется традиционное выражение функции, а во втором — стрелочная функция.

Однако, если мы запустим их в консоли с одинаковыми аргументами, то получим разные результаты.

const anon = test.createAnonFunction('hello', 'world'); const arrow = test.createArrowFunction('hello', 'world'); anon(); undefined > arrow(); test object  '0': 'hello', '1': 'world' >

У анонимной функции есть свой собственный контекст функции, поэтому при ее вызове отсутствует доступная ссылка на this.name объекта test и на аргументы, вызываемые при его создании.

Стрелочная функция, с другой стороны, имеет тот же контекст функции, что и функция, которая ее создала, предоставляя ей доступ как к аргументам, так и к объекту test.

Стрелочные функции всегда являются анонимными

Еще одна вещь, которую ты должен знать о стрелочных функциях, по крайней мере сейчас (может изменится в будущих версиях JavaScript) это то, что стрелочные функции всегда являются анонимными.

Так что же такое анонимная функция? На самом деле, что такое именная функция?

Именная функция выглядит примерно так:

function sayMyName(name)  alert(`Hello $name>`); >

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

Если ты используешь стрелочную функцию, то ты не можешь назвать их. Ни одна из наших стрелочных функций не имеет имени. Ты можешь, поместить ее в переменную, например:

const sayMyName = (name) =>  alert(`Hello $name>!`); >; sayMyName("Alex");

Нужно понимать, что анонимную функцию, трудно отследить в стеке вызовов. Однако, если ты не слишком обеспокоен этим, можешь продолжать их использовать.

Когда не нужно использовать стрелочные функции

Перед тем, как начать использовать стрелочные функции везде, нам нужно поболтать. Стрелочные функции не заменяют обычные функции. Так же, как Flexbox и floats , pixels и rems , более старая вещь всё еще сохраняет много полезного, потому что она работает не так, как новая.

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

У нас есть большая кнопка Push me.

style> button  font-size: 50px; > .on  background: yellow; > style> button id="push">Push mebutton>

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

const button = document.querySelector("#push"); button.addEventListener("click", () =>  this.classList.toggle("on"); >);

Но если мы нажмем на кнопку, то получим ошибку в консоли: TypeError, cannot read property ‘toggle’ of undefined .

Если помнишь, у браузера есть атрибут window . Если выведешь в консоль this , то увидишь что он равен window :

const button = document.querySelector("#push"); button.addEventListener("click", () =>  console.log("this is", this); // this is window! this.classList.toggle("on"); >);

Если мы используем стрелочную функцию, то слово this не привязано к этому элементу. Если мы используем обычную функцию, то слово this будет связано с элементом, на который мы нажали!

const button = document.querySelector("#push"); button.addEventListener("click", function ()  console.log("this is", this); // current element this.classList.toggle("on"); >);

В консоли this теперь наша кнопка, и она работает.

Теперь, давайте посмотрим на следующий пример, когда нужно привязать метод к объекту.

const person =  points: 23, score: () =>  this.points++; >, >;

У нас есть метод score , и всякий раз, когда мы вызываем person.score , он должен добавить нам еще один балл, который в настоящее время равны 23.

Если мы запустим person.score(); два раза, у нас должно быть 25 баллов. Но у нас по прежнему 23. Почему?

Потому что он пытается добавить баллы в window ! Помни, что при использовании стрелочной функции this не связано ни с чем, а просто наследует его от родительской области, которая в данном случае является window.

Итак, давай сделаем то же самое с обычной функцией:

const person =  points: 23, score: function ()  this.points++; >, >;

Теперь всё работает.

В качестве третьего примера мы поговорим о том, когда нам нужно будет добавить метод-прототипа.

class Developer  constructor(name, dev)  this.name = name; this.dev = dev; > >

Например, у нас есть класс. Если ты еще не слышал о классах, то достаточно знать, что это способ для нас создавать новых разработчиков.

Также, есть конструктор класса, куда, когда ты вызываешь new Developer , мы передаем имя человека (name), а также, чем он занимается (dev).

Мы создаем двух разработчиков:

const front = new Developer("Alex", "Frontend"); const back = new Developer("John", "Backend");

Вызвав их в консоль, ты увидишь, что front возвращается как Developer , и back вернется как Developer .

Теперь, добавим метод-прототипа:

Developer.prototype.hello = () =>  return `Hello, my name is $this.name> and I am a $this.dev> developer`; >;

Это позволяет нам сделать так, что даже после того, как эти разработчики были созданы, мы можем добавить методы ко всем из них. Итак, наш метод Developer.prototype.hello установлен, поэтому давай выведем в консоль: front.hello() .

Несмотря на то, что мы добавили метод после создания разработчиков Developer, (поскольку мы добавили его в прототип) он доступен в каждом объекте, который был создан оттуда.

Что делает этот прототип, так это возвращает this.name и this.dev в строку.

Однако в нашем примере this.name и this.dev не определены. Почему?

Потому что мы стараемся быть крутыми и использовать стрелочную функцию. Почему мы не используем стрелочную функцию здесь? Потому что нам нужно ключевое слово this, поэтому вы должны использовать обычную функцию:

Developer.prototype.hello = function ()  return `Hello, my name is $this.name> and I am a $this.dev> developer`; >;

Теперь, если мы вызовем front.hello() , то он выведет Hello, my name is Alex and I am a Frontend developer , а если back.hello() , мы получаем Hello, my name is John and I am a Backend developer . Опять же, ты должен использовать обычную функцию для этого.

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

как вернуть значение из функции js

Чтобы вернуть некое значение из функции используется ключевое слово return . В качестве значения может быть что угодно, в зависимости от цели и задачи для этой функции.

Пример ниже показывает функцию, которая возвращает значения типа boolean . Такие функции называются предикатами.

function isHero(person)  return person.name === 'Harry Potter'; > const person = 'Huge Plotter'; isHero(person); // false 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *