Перейти к содержимому

Как вызвать функцию внутри другой функции js

  • автор:

Вызвать функцию из функции JavaScript

Я только начал изучать JavaScript. Надо вызвать функцию, из функции пытаюсь не получается. Помогите пожалуйста. Код:

 self.AutoSearch = function (searchPanelUpdateRequired, isMobileOverride, function ());>) < var windowWidth = document.documentElement.clientWidth; if ((windowWidth >500) || (isMobileOverride == true)) < if (self.SearchData.Configuration.SearchAutoUpdate()) < self.DoSearch(1, searchPanelUpdateRequired, false); >else < if (searchPanelUpdateRequired != false) < self.UpdateSearchPanel(); >> > return true; > 

Отслеживать

9,333 3 3 золотых знака 29 29 серебряных знаков 57 57 бронзовых знаков

задан 29 янв 2018 в 10:25

Исмоил Мухаммадиев Исмоил Мухаммадиев

327 2 2 золотых знака 6 6 серебряных знаков 19 19 бронзовых знаков

Пять способов вызвать функцию

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

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

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

function makeArray(arg1, arg2)
Самый распространенный способ: глобальный вызов

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

makeArray('one', 'two'); // => [ window, 'one', 'two' ] 

Погодите. Откуда взялся объект window ? Почему это у нас this равен window ?

В JavaScript, неважно, выполняется ли скрипт в браузере или в ином окружении, всегда определен глобальный объект. Любой код в нашем скрипте, не «привязанный» к чему-либо (т.е. находящийся вне объявления объекта) на самом деле находится в контексте глобального объекта. В нашем случае, makeArray — не просто функция, «гуляющая» сама по себе. На самом деле, makeArray — метод глобального объекта (в случае исполнения кода в браузере) window . Доказать это легко:

alert( typeof window.methodThatDoesntExist ); // => undefined alert( typeof window.makeArray ); // => function 

То есть вызов makeArray(‘one’, ‘two’); равносилен вызову window.makeArray(‘one’, ‘two’); .

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

Правило вызова функций №1: Если функция вызывается напрямую, без указания объекта (например, myFunction() ), значением this будет глобальный объект ( window в случае исполнения кода в браузере).

Вызов метода

Давайте создадим простой объект и сделаем makeArray его методом. Объект объявим с помощью литеральной нотации, а после вызовем наш метод:

// создаем объект var arrayMaker = < someProperty: 'какое-то значение', make: makeArray >; // вызываем метод make() arrayMaker.make('one', 'two'); // => [ arrayMaker, 'one', 'two' ] // альтернативный синтаксис, используем квадратные скобки arrayMaker['make']('one', 'two'); // => [ arrayMaker, 'one', 'two' ] 

Видите разницу? Значение this в этом случае — сам объект. Почему не window , как в предыдущем случае, ведь объявление функции не изменилось? Весь секрет в том, как передаются функции в JavaScript. Function — это стандартный тип JavaScript, являющийся на самом деле объектом, и как и любой другой объект, функции можно передавать и копировать. В данном случае, мы как бы скопировали всю функцию, включая список аргументов и тело, и присвоили получившийся объект свойству make объекта arrayMaker . Это равносильно такому объявлению:

var arrayMaker = < someProperty: 'Какое-то значение'; make: function (arg1, arg2) < return [ this, arg1, arg2]; >>; 

Правило вызова функций №2: В функции, вызванной с использованием синтаксиса вызова метода, например, obj.myFunction() или obj[‘myFunction’]() , this будет иметь значение obj .

Непонимание этого простого, в общем-то, принципа часто приводит к ошибкам при обработке событий:

     

Щелчок по первой кнопке покажет сообщение «btn1», потому что в данном случае мы вызываем функцию как метод, и this внутри функции получит значение объекта, которому этот метод принадлежит. Щелчок по второй кнопке выдаст «window», потому что в этом случае мы вызываем buttonClicked напрямую (т.е. не как obj.buttonClicked() ). То же самое происходит, когда мы назначаем обработчик события в тэге элемента, как в случае третьей кнопки. Щелчок по третьей кнопке покажет то же самое сообщение, что и для второй.

При использовании библиотек вроде jQuery думать об этом не надо. jQuery позаботится о том, чтобы переписать значение this в обработчике события так, чтобы значением this был элемент, вызвавший событие:

// используем jQuery $('#btn1').click( function() < alert( this.id ); // jQuery позаботится о том, чтобы 'this' являлась кнопкой >); 

Каким образом jQuery удается изменить значение this ? Читайте ниже.

Еще два способа: apply() и call()

Логично, что чем чаще вы используете функции, тем чаще вам приходится передавать их и вызывать в разных контекстах. Зачастую возникает необходимость переопределить значение this . Если вы помните, функции в JavaScript являются объектами. На практике это означает, что у функций есть предопределенные методы. apply() и call() — два из них. Они позволяют переопределять значение this :

var car = < year: 2008, model: 'Dodge Bailout' >; makeArray.apply( car, [ 'one', 'two' ] ); // => [ car, 'one', 'two' ] makeArray.call( car, 'one', 'two' ); // => [ car, 'one', 'two' ] 

Эти два метода очень похожи. Первый параметр переопределяет this . Различия между ними заключаются в последющих аргументах: Function.apply() принимает массив значений, которые будут переданы функции, а Function.call() принимает аргументы раздельно. На практике, по моему мнению, удобнее применять apply() .

Правило вызова функций №3: Если требуется переопределить значение this , не копируя функцию в другой объект, можно использовать myFunction.apply( obj ) или myFunction.call( obj ) .

Конструкторы

Я не буду подробно останавливаться на объявлении собственных типов в JavaScript, но считаю необходимым напомнить, что в JavaScript нет классов, а любой пользовательский тип нуждается в конструкторе. Кроме того, методы пользовательского типа лучше объявлять через prototype , который является свойством фукции-конструктора. Давайте создадим свой тип:

// объявляем конструктор function ArrayMaker(arg1, arg2) < this.someProperty = 'неважно'; this.theArray = [ this, arg1, arg2 ]; >// объявляем методы ArrayMaker.prototype = < someMethod: function () < alert('Вызван someMethod'); >, getArray: function () < return this.theArray; >>; var am = new ArrayMaker( 'one', 'two' ); var other = new ArrayMaker( 'first', 'second' ); am.getArray(); // => [ am, 'one', 'two' ] 

Важным в этом примере является наличие оператора new перед вызовом функции. Если бы не он, это был бы глобальный вызов, и создаваемые в конструкторе свойства относились бы к глобальному объекту. Нам такого не надо. Кроме того, в конструкторах обычно не возвращают значения явно. Без оператора new конструктор вернул бы undefined , с ним он возвращает this . Хорошим стилем считается наименование конструкторов с заглавной буквы; это позволит вспомнить о необходимости оператора new .

В остальном, код внутри конструктора, скорее всего, будет похож на код, который вы написали бы на другом языке. Значение this в данном случае — это новый объект, который вы создаете.

Правило вызова функций №4: При вызове функции с оператором new , значением this будет новый объект, созданный средой исполнения JavaScript. Если эта функция не возвращает какой-либо объект явно, будет неявно возвращен this .

Заключение

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

Как в javascript можно вызвать функцию

Второй способ — это передать нашу функцию в другую функцию в качестве аргумента. Передаваемая функция будет назваться «функцией обратного вызова» или «колбэк-функцией», а её вызов произойдет по завершению какого-либо действия (например, выполнения другой функции, истечения времени таймера, наступления события на странице и т.д.):

const getMessage = (greeting, callback) =>  console.log(greeting); // функция callback() будет вызвана после выполнения console.log(greeting) callback(); >; getMessage('Hi!', myFunction); // => Hi! It's my function! 
// в этом примере функция myFunction() будет вызвана после истечения времени в 1000 миллисекунд (1 секунда) setTimeout(myFunction, 1000); // => It's my function! 

17 января 2022

Очень просто. Допустим у нас есть функция getSum() , которая вычисляет сумму двух чисел и возвращает результат. Вызов этой функции будет выглядеть так:

getSum(1, 3); 

Тут мы передаём в нашу функцию два параметра 1 и 3, а вернуть она должна число 4.

Возврат функций из функций — JS: Функциональное программирование

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

Для закрепления материала пройдитесь по нему два раза. Первый раз просто бегло прочитайте, второй раз изучите внимательно, проверяя каждую строчку кода на сервисе repl.it .

Начнем погружение с уже пройденного материала:

const identity = (v) => v; identity('wow'); // wow const sum = identity((a, b) => a + b); sum(1, 8); // 9 

Функции — это такие же данные, как числа или строки, поэтому функции можно передавать в другие функции в виде аргументов, а также возвращать из функций. Мы даже можем определить функцию внутри другой функции и вернуть ее наружу. И в этом нет ничего удивительного. Константы можно создавать где угодно.

const generateSumFinder = () =>  const sum = (a, b) => a + b; // создали функцию return sum; // и вернули ее >; const sum = generateSumFinder(); // sum теперь — функция, которую вернула функция generateSumFinder sum(1, 5); // 6 // sum складывает числа 

Можно даже обойтись без промежуточного создания константы:

// вызвали функцию, которая возвращает функцию, // и тут же вызвали возвращенную функцию generateSumFinder()(1, 5); // 6 // ((a, b) => a + b)(1, 5) 

Всегда, когда видите подобные вызовы f()()() , знайте: функции возвращаются!

Теперь посмотрим, как еще можно описать функцию generateSumFinder :

// предыдущий вариант для сравнения // const generateSumFinder = () => // const sum = (a, b) => a + b; // return sum; // >; // новый вариант const generateSumFinder = () => (a, b) => a + b; 

Для понятности можно расставить скобки:

const generateSumFinder = () => ((a, b) => a + b); 

Определение функции обладает правой ассоциативностью. Все, что находится справа от => , считается телом функции. Количество вложений никак не ограничено. Вполне можно встретить и такие варианты:

const sum = (x) => (y) => (z) => x + y + z; // расставим скобки для того чтобы увидеть как функции вложены друг в друга // const sum = x => (y => (z => x + y + z)); sum(1)(3)(5); // 9 

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

const inner1 = (z) => x + y + z; const inner2 = (y) => inner1; const sum = (x) => inner2; 

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

sum(1)(3)(5); // 9 const sum1 = (x) => (y) => (z) => x + y + z; // sum(1); const sum2 = (y) => (z) => 1 + y + z; // inner2 // sum(1)(3) const sum3 = (z) => 1 + 3 + z; // inner1 // sum(1)(3)(5) const sum4 = 1 + 3 + 5; // 9 

Как видно выше, sum1 , sum2 и sum3 — это функции, а sum4 уже число, так как были вызваны все внутренние функции.

Давайте распишем все функции:

const sum = (x) => (y) => (z) => x + y + z; // const sum = x => (y => (z => x + y + z)); 
  • Функция sum принимает x и возвращает функцию, которая
    • принимает y и возвращает функцию, которая
      • принимает z и возвращает сумму x + y + z

      Попробуем развить идею функции callTwice из предыдущего урока. Напишем функцию generate , которая не применяет функцию сразу, а генерирует новую.

      const generate = (f) => (arg) => f(f(arg)); // const generate = f => (arg => f(f(arg))); 

      Функция generate принимает функцию в качестве аргумента и возвращает новую функцию. Внутри новой функции переданная изначально функция вызывается два раза:

      Создадим функцию f1 . Она будет той функцией, которую вернет generate если передать ей функцию Math.sqrt (она вычисляет квадратный корень числа).

      Получается, f1 — это функция, которая принимает число и возвращает корень корня — Math.sqrt(Math.sqrt(x)) :

      const f1 = generate(Math.sqrt); f1(16); // 2 // generate(Math.sqrt)(16); 

      Еще пример: передадим в функцию generate новую функцию на ходу, без предварительного создания. Переданная функция возводит число в квадрат.

      const f2 = generate(x => x ** 2); f2(4); // 256 // generate(x => x ** 2)(4); 

      Теперь функция f2 возводит число в квадрат два раза: (4 2 ) 2 .

      Функция generate имеет такое имя не просто так. Дело в том, что возврат функции порождает каждый раз новую функцию при каждом вызове, даже если тела этих функций совпадают:

      const f1 = generate(x => x ** 2); const f2 = generate(x => x ** 2); console.log(f1 === f2); // => false 

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

      Замыкание

      Работа практически всех описанных примеров базировалась на одном интересном свойстве, которое называется «замыкание». О нем говорилось в предыдущем курсе, но пришло время освежить память.

      const generateDouble = (f) => (arg) => f(f(arg)); const f1 = generateDouble(Math.sqrt); 

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

      Но та функция, которую вернула generateDouble , все еще использует аргумент. В обычных условиях он бы навсегда исчез, но тут он «запомнился» или «замкнулся» внутри возвращенной функции. Технически внутренняя функция, как и любая другая в JavaScript, связана со своим лексическим окружением, которое не пропадает, даже если функция покидает это окружение.

      Функция, которая была возвращена из generateDouble , называется замыканием. Замыкание — это функция, «запомнившая» часть окружения, где она была задана. Функция замыкает в себе идентификаторы (все, что мы определяем) из лексической области видимости.

      В СИКП дается прекрасный пример на понимание замыканий. Представьте себе, что мы проектируем систему, в которой нужно запомнить пароль пользователя, а потом проверять его, когда пользователь будет заново заходить. Можно смоделировать функцию savePassword , которая принимает на вход пароль и возвращает предикат, то есть функцию, возвращающую true или false, для его проверки. Посмотрите, как это выглядит:

      const secret = 'qwerty'; // Возвращается предикат. const isCorrectPassword = savePassword(secret); // Теперь можно проверять console.log(isCorrectPassword('wrong password')); // => false console.log(isCorrectPassword('qwerty')); // => true 

      А вот как выглядит код функции savePassword :

      const savePassword = password => passwordForCheck => password === passwordForCheck; 

      Возврат функций в реальном мире (Debug)

      Логгирование — неотъемлемая часть разработки. Для понимания того, что происходит внутри кода, используют специальные библиотеки, с помощью которых можно логгировать (выводить) информацию о проходящих внутри процессах, например в файл. Типичный лог веб-сервера, обрабатывающего HTTP-запросы выглядит так:

      В JavaScript самой популярной библиотекой для логгирования считается Debug . Вот как выглядит ее вывод:

      Обратите внимание на левую часть каждой строки. Debug для каждой выводимой строчки использует так называемый неймспейс, некоторую строчку, которая указывает принадлежность выводимой строчки к определенной подсистеме или части кода. Он используется для фильтрации, когда логов становится много. Другими словами, можно указать «выводи сообщения только для http». А вот как это работает:

      import debug from 'debug'; const logHttp = debug('http'); const logHandler = debug('handler'); logHttp('hello!'); logHttp('i am from http'); logHandler('hello from handler!'); logHandler('i am from handler'); 

      Что приведет к такому выводу:

      Открыть доступ

      Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

      • 130 курсов, 2000+ часов теории
      • 1000 практических заданий в браузере
      • 360 000 студентов

      Наши выпускники работают в компаниях:

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

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