Как объявить функцию в javascript. Функциональное программирование. Объявление и вызов функции JavaScript

Любому программисту хорошо известно, что такое функции и зачем они нужны. Однако функциям в языке Javascript присущи некоторые особенности. Если вы давно программируете именно на этом языке, то наверняка знаете, что существуют разные . Если же вы пришли из другого языка, то при прочтении некоторых статей скорее всего видели вот такое, странное на первый взгляд, объявление функции:

Var add = function(arg1, arg2) { var sum = arg1 + arg2; return sum; } var result = add(5, 2); //result теперь 7

То есть функция, во-первых, не имеет имени. Во-вторых, она присваивается переменной, но не просто присваивается, а тут же идет ее тело. Лично у меня, до этого писавшего на таких языках как VB, C++, подобное объявление вызывало недоумение и непонимание, как это устроено и зачем вообще так писать.

Я привык к "классическому" объявлению функции и ее вызову, вот так:

Function add(arg1, arg2) { var sum = arg1 + arg2; return sum; } var result = add(5, 3); //result теперь 8

И вот здесь как раз мы подходим к особенностям функций в Javascript. Для простоты понимания представьте себе, что функция в JS - это обычное значение, как, например, число или строка. Вы же можете записать в переменную result число 5? Или что-то более сложное, вроде массива, а потом вывести это на экран? Можете. Так вот, если представить, что функция - это обычное значение, пусть и весьма сложной структуры, то первый способ объявления уже не кажется чем-то невероятным.

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

Var a = 5; var b = a; alert(b); //выведет 5

Обычное дело. А теперь взгляните вот на этот код:

Var add = function(arg1, arg2) { var sum = arg1 + arg2; return sum; } var calcSum = add; alert(calcSum(5, 6)); //выведет 11

Начинаете уже догадываться? Поскольку функция - как переменная, мы можем "размножать" ее посредством обычного присваивания в другие переменные, превращая их так же в функции. Теперь calcSum тоже умеет складывать два числа. Однако код

Var calcSum = add(1, 1); //calcSum теперь равно 2, это не функция, а переменная с числом alert(calcSum(5, 6)); //ошибка

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

Если вам понадобится вызвать функцию в самой себе, то это делается следующим образом:

Var calcFact = function fact(val) { if (val == 1) ? val: val * fact(val — 1); //вычисление факториала с помощью рекурсии } alert(calcFact(4)); //выведет 24

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

Возможно, вы задаетесь вопросом "Хм, интересная возможность! Но какое преимущество у этого способа? Есть ли ситуации, когда без этого не обойтись или это хотя бы более удобно, чем обычное объявление?". Не возьмусь утверждать, что есть ситуации, где без такого подхода обойтись нельзя, но пример, где он уменьшает количество кода, привести могу. Допустим, вам нужно поприветствовать человека в зависимости от времени суток:

Var date = new Date(); var hello = (date.getHours() < 12) ? function() {alert("Доброе утро!")} : (date.getHours() < 18) ? function() {alert("Добрый день!")} : function() {alert("Добрый вечер!")}; hello();

Как видите, функции крайне простые, с одной-единственной командой alert.

Если бы мы решили пойти "классическим путем", то пришлось бы писать три отдельные функции, а потом вызывать их в условии проверки времени:

Function goodMorning() { alert("Доброе утро!"); } function goodAfternoon() { alert("Добрый день!"); } function goodEvning() { alert("Добрый вечер!"); } var date = new Date(); (date.getHours() < 12) ? goodMorning() : (date.getHours() < 18) ? goodAfternoon() : goodEvning();

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

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

Function add(a, b) { return a + b; } var calcSum = add; calcSum(5, 5);

Уже нельзя. Поэтому в нашем примере, если все-таки понадобится приветствовать гостя не единожды, нам придется каждый раз дублировать вот этот фрагмент:

(date.getHours() < 12) ? goodMorning() : (date.getHours() < 18) ? goodAfternoon() : goodEvning();

А в первом случае достаточно будет написать всего лишь hello(); и результат будет тот же.

Я рассказал вам про интересную особенность функций JS и привел примеры. Таким образом вы увидели, что способы вызова функций в Javascript не ограничиваются одним-единственным видом. Даже если вы и не сможете сразу найти применение этим возможностям в ваших проектах, то хотя бы будете знать, что такие возможности есть. И когда подвернется действительно удачный случай, то сможете сократить объем кода и избежать лишней путаницы и ошибок.!

Функции - ключевая концепция в JavaScript. Важнейшей особенностью языка является первоклассная поддержка функций ​ (functions as first-class citizen) . Любая функция это объект, и следовательно ею можно манипулировать как объектом, в частности:

  • передавать как аргумент и возвращать в качестве результата при вызове других функций (функций высшего порядка);
  • создавать анонимно и присваивать в качестве значений переменных или свойств объектов.

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

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

Для понимания работы функций необходимо (и достаточно?) иметь представление о следующих моментах:

Объявление функций Функции вида "function declaration statement"

Объявление функции (function definition , или function declaration , или function statement ) состоит из ключевого слова function и следующих частей:

  • Имя функции.
  • Список параметров (принимаемых функцией) заключенных в круглые скобки () и разделенных запятыми.
  • Инструкции, которые будут выполненны после вызова функции, заключают в фигурные скобки { } .

Например, следующий код объявляет простую функцию с именим square:

Function square(number) { return number * number; }

Функция square принимает один параметр, названный number. Состоит из одной инструкции, которая означает вернуть параметр этой функции (это number) умноженный на самого себя. Инструкция return указывает на значение, которые будет возвращено функцией.

Return number * number;

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

Если Вы передадите объект как параметр (не примитив, например, или определяемые пользователем объкты), и функция изменит свойство переданного в неё объекта, это изменение будет видно и вне функции, как показано в следующим примере:

Function myFunc(theObject) { theObject.make = "Toyota"; } var mycar = {make: "Honda", model: "Accord", year: 1998}; var x, y; x = mycar.make; // x получает значение "Honda" myFunc(mycar); y = mycar.make; // y получает значение "Toyota" // (свойство было изменено функцией)

Функции вида "function definition expression"

Функция вида "function declaration statement" по синтаксису является инструкцией (statement ), ещё функция может быть вида "function definition expression". Такая функция может быть анонимной (она не имеет имени). Например, функция square может быть вызвана так:

Var square = function(number) { return number * number; }; var x = square(4); // x получает значение 16

Однако, имя может быть и присвоено для вызова самой себя внутри самой функции и для отладчика (debugger ) для идентифицирования функции в стек-треках (stack traces ; "trace" - "след" / "отпечаток").

Var factorial = function fac(n) { return n < 2 ? 1: n * fac(n - 1); }; console.log(factorial(3));

Функции вида "function definition expression" удобны, когда функция передается аргументом другой функции. Следующий пример показывает функцию map , которая должна получить функцию первым аргументом и массив вторым.

Function map(f, a) { var result = , // Create a new Array i; for (i = 0; i != a.length; i++) result[i] = f(a[i]); return result; }

В следующим коде наша функция принимает функцию, которая является function definition expression, и выполняет его для каждого элемента принятого массива вторым аргументом.

Function map(f, a) { var result = ; // Create a new Array var i; // Declare variable for (i = 0; i != a.length; i++) result[i] = f(a[i]); return result; } var f = function(x) { return x * x * x; } var numbers = ; var cube = map(f,numbers); console.log(cube);

Функция возвращает: .

В JavaScript функция может быть объявлена с условием. Например, следующая функция будет присвоена переменной myFunc только, если num равно 0:

Var myFunc; if (num === 0) { myFunc = function(theObject) { theObject.make = "Toyota"; } }

В дополнение к объявлениям функций, описанных здесь, Вы также можете использовать конструктор Function для создания функций из строки во время выполнения (runtime ), подобно .

Метод - это функция, которая является свойством объекта. Узнать больше про объекты и методы можно по ссылке: Работа с объектами .

Вызовы функций

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

Square(5);

Эта инструкция вызывает функцию с аргументом 5. Функция вызывает свои инструкции и возвращает значение 25.

Функции могут быть в области видимости, когда они уже определены, но функции вида "function declaration statment" могут быть подняты (поднятие - hoisting ), также как в этом примере:

Console.log(square(5)); /* ... */ function square(n) { return n * n; }

Область видимости функции - функция, в котором она определена, или целая программа, если она объявлена по уровню выше.

Примечание: Это работает только тогда, когда объявлении функции использует вышеупомянутый синтаксис (т.е. function funcName(){}). Код ниже не будет работать. Имеется в виду то, что поднятие функции работает только с function declaration и не работает с function expression.

Console.log(square); // square поднят со значением undefined. console.log(square(5)); // TypeError: square is not a function var square = function(n) { return n * n; }

Аргументы функции не ограничиваются строками и числами. Вы можете передавать целые объекты в функцию. Функция show_props() (объявленная в Работа с объектами) является примером функции, принимающей объекты аргументом.

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

Function factorial(n) { if ((n === 0) || (n === 1)) return 1; else return (n * factorial(n - 1)); }

Затем вы можете вычислить факториалы от одного до пяти следующим образом:

Var a, b, c, d, e; a = factorial(1); // a gets the value 1 b = factorial(2); // b gets the value 2 c = factorial(3); // c gets the value 6 d = factorial(4); // d gets the value 24 e = factorial(5); // e gets the value 120

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

Область видимости функций

(function scope)

Переменные объявленные в функции не могут быть доступными где-нибудь вне этой функции, поэтому переменные (которые нужны именно для функции) объявляют только в scope функции. При этом функция имеет доступ ко всем переменным и функциям, объявленным внутри её scope. Другими словами функция объявленная в глобальном scope имеет доступ ко всем переменным в глобальном scope. Функция объявленная внутри другой функции ещё имеет доступ и ко всем переменным её родителькой функции и другим переменным, к которым эта родительская функция имеет доступ.

// Следующие переменные объявленны в глобальном scope var num1 = 20, num2 = 3, name = "Chamahk"; // Эта функция объявленна в глобальном scope function multiply() { return num1 * num2; } multiply(); // вернет 60 // Пример вложенной функции function getScore() { var num1 = 2, num2 = 3; function add() { return name + " scored " + (num1 + num2); } return add(); } getScore(); // вернет "Chamahk scored 5"

Scope и стек функции

(function stack)

Рекурсия

Функция может вызывать саму себя. Три способа такого вызова:

  • по имени функции
  • по переменной, которая ссылается на функцию
  • Для примера рассмотрим следующие функцию:

    Var foo = function bar() { // statements go here };

    Внутри функции (function body ) все следующие вызовы эквивалентны:

  • bar()
  • arguments.callee()
  • foo()
  • Функция, которая вызывает саму себя, называется рекурсивной функцией (recursive function ). Получается, что рекурсия аналогична циклу (loop ). Оба вызывают некоторый код несколько раз, и оба требуют условия (чтобы избежать бесконечного цикла, вернее бесконечной рекурсии). Например, следующий цикл:

    Var x = 0; while (x < 10) { // "x < 10" - это условие для цикла // do stuff x++; }

    можно было изменить на рекурсивную функцию и вызовом этой функции:

    Function loop(x) { if (x >= 10) // "x >= 10" - это условие для конца выполения (тоже самое, что "!(x < 10)") return; // делать что-то loop(x + 1); // рекурсионный вызов } loop(0);

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

    Function walkTree(node) { if (node == null) // return; // что-то делаем с элементами for (var i = 0; i < node.childNodes.length; i++) { walkTree(node.childNodes[i]); } }

    В сравнении с функцией loop , каждый рекурсивный вызов сам вызывает много рекурсивных вызовов.

    Также возможно превращение некоторых рекурсивных алгоритмов в нерекурсивные, но часто их логика очень сложна, и для этого потребуется использование стека (stack ). По факту рекурсия использует stach: function stack.

    Поведение stack"а можно увидеть в следующем примере:

    Function foo(i) { if (i < 0) return; console.log("begin: " + i); foo(i - 1); console.log("end: " + i); } foo(3); // Output: // begin: 3 // begin: 2 // begin: 1 // begin: 0 // end: 0 // end: 1 // end: 2 // end: 3

    Вложенные функции (nested functions) и замыкания (closures)

    Вы можете вложить одну функцию в другую. Вложенная функция (nested function ; inner ) приватная (private ) и она помещена в другую функцию (outer ). Так образуется замыкание (closure ). Closure - это выражение (обычно функция), которое может иметь свободные переменные вместе со средой, которая связывает эти переменые (что "закрывает" ("close" ) выражение).

    Поскольку вложенная функция это closure, это означает, что вложенная функция может "унаследовать" (inherit ) аргументы и переменные функции, в которую та вложена. Другими словами, вложенная функция содержит scope внешней ("outer" ) функции.

    Подведем итог:

    • Вложенная функция имеет доступ ко всем инструкциям внешней функции.
    • Вложенная функция формирует closure: она может использовать аргументы и переменные внешней функции, в то время как внешняя функция не может использовать аргументы и переменные вложенной функции.

    Следующий пример показывает вложенную функцию:

    Function addSquares(a, b) { function square(x) { return x * x; } return square(a) + square(b); } a = addSquares(2, 3); // возвращает 13 b = addSquares(3, 4); // возвращает 25 c = addSquares(4, 5); // возвращает 41

    Поскольку вложенная функция формирует closure, Вы можете вызвать внешную функцию и указать аргументы для обоих функций (для outer и innner).

    Function outside(x) { function inside(y) { return x + y; } return inside; } fn_inside = outside(3); // Подумайте над этим: дайте мне функцию, // который передай 3 result = fn_inside(5); // возвращает 8 result1 = outside(3)(5); // возвращает 8

    Сохранение переменных

    Обратите внимание, значение x сохранилось, когда возвращалось inside . Closure должно сохранять аргументы и переменные во всем scope. Поскольку каждый вызов предоставляет потенциально разные аргументы, создается новый closure для каждого вызова во вне. Память может быть очищена только тогда, когда inside уже возвратился и больше не доступен.

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

    Несколько уровней вложенности функций (Multiply-nested functions)

    Функции можно вкадывать несколько раз, т.е. функция (A) хранит в себе функцию (B), которая хранит в себе функцию (C). Обе фукнкции B и C формируют closures, так B имеет доступ к переменным и аргументам A, и C имеет такой же доступ к B. В добавок, поскольку C имеет такой доступ к B, который имеет такой же доступ к A, C ещё имеет такой же доспут к A. Таким образом cloures может хранить в себе несколько scope; они рекурсивно хранят scope функций, содержащих его. Это называется chaining (chain - цепь ; Почему названо "chaining" будет объяснено позже)

    Рассмотрим следующий пример:

    Function A(x) { function B(y) { function C(z) { console.log(x + y + z); } C(3); } B(2); } A(1); // в консоле выведится 6 (1 + 2 + 3)

    В этом примере C имеет доступ к y функции B и к x функции A . Так получается, потому что:

  • Функция B формирует closure, включающее A , т.е. B имеет доступ к аргументам и переменным функции A .
  • Функция C формирует closure, включающее B .
  • Раз closure функции B включает A , то closure С тоже включает A, C имеет доступ к аргументам и переменным обоих функций B и A . Другими словами, С cвязывает цепью (chain ) scopes функций B и A в таком порядке.
  • В обратном порядке, однако, это не верно. A не имеет доступ к переменным и аргументам C , потому что A не имеет такой доступ к B . Таким образом, C остается приватным только для B .

    Конфликты имен (Name conflicts)

    Когда два аргумента или переменных в scope у closure имеют одинаковые имена, происходит конфликт имени (name conflict ). Более вложенный (more inner ) scope имеет приоритет, так самый вложенный scope имеет наивысший приоритет, и наоборот. Это цепочка областей видимости (scope chain ). Самым первым звеном является самый глубокий scope, и наоборот. Рассмотрим следующие:

    Function outside() { var x = 5; function inside(x) { return x * 2; } return inside; } outside()(10); // возвращает 20 вместо 10

    Конфликт имени произошел в инструкции return x * 2 между параметром x функции inside и переменной x функции outside . Scope chain здесь будет таким: { inside ==> outside ==> глобальный объект (global object )}. Следовательно x функции inside имеет больший приоритет по сравнению с outside , и нам вернулось 20 (= 10 * 2), а не 10 (= 5 * 2).

    Замыкания

    (Closures)

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

    Однако, внешняя функция не имеет доступа к переменным и функциям, объявленным во внутренней функции. Это обеспечивает своего рода инкапсуляцию для переменных внутри вложенной функции.

    Также, поскольку вложенная функция имеет доступ к scope внешней функции, переменные и функции, объявленные во внешней функции, будет продолжать существовать и после её выполнения для вложенной функции, если на них и на неё сохранился доступ (имеется ввиду, что переменные, объявленные во внешней функции, сохраняются, только если внутренняя функция обращается к ним).

    Closure создается, когда вложенная функция как-то стала доступной в неком scope вне внешней функции.

    Var pet = function(name) { // Внешняя функция объявила переменную "name" var getName = function() { return name; // Вложенная функция имеет доступ к "name" внешней функции } return getName; // Возвращаем вложенную функцию, тем самым сохраняя доступ // к ней для другого scope } myPet = pet("Vivie"); myPet(); // Возвращается "Vivie", // т.к. даже после выполнения внешней функции // name сохранился для вложенной функции

    Более сложный пример представлен ниже. Объект с методами для манипуляции вложенной функции внешней функцией можно вернуть (return ).

    Var createPet = function(name) { var sex; return { setName: function(newName) { name = newName; }, getName: function() { return name; }, getSex: function() { return sex; }, setSex: function(newSex) { if(typeof newSex === "string" && (newSex.toLowerCase() === "male" || newSex.toLowerCase() === "female")) { sex = newSex; } } } } var pet = createPet("Vivie"); pet.getName(); // Vivie pet.setName("Oliver"); pet.setSex("male"); pet.getSex(); // male pet.getName(); // Oliver

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

    Var getCode = (function() { var apiCode = "0]Eal(eh&2"; // A code we do not want outsiders to be able to modify... return function() { return apiCode; }; }()); getCode(); // Returns the apiCode

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

    Var createPet = function(name) { // The outer function defines a variable called "name". return { setName: function(name) { // The enclosed function also defines a variable called "name". name = name; // How do we access the "name" defined by the outer function? } } }

    Использование объекта arguments

    Объект arguments функции является псевдо-массивом. Внутри функции Вы можете ссылаться к аргументам следующим образом:

    Arguments[i]

    где i - это порядковый номер аргумента, отсчитывающийся с 0. К первому аргументу, переданному функции, обращаются так arguments . А получить количество всех аргументов - arguments.length .

    С помощью объекта arguments Вы можете вызвать функцию, передавая в неё больше аргументов, чем формально объявили принять. Это очень полезно, если Вы не знаете точно, сколько аргументов должна принять Ваша функция. Вы можете использовать arguments.length для определения количества аргументов, переданных функции, а затем получить доступ к каждому аргументу, используя объект arguments .

    Для примера рассмотрим функцию, которая конкатенирует несколько строк. Единственным формальным аргументом для функции будет строка, которая указывает символы, которые разделяют элементы для конкатенации. Функция определяется следующим образом:

    Function myConcat(separator) { var result = ""; var i; // iterate through arguments for (i = 1; i < arguments.length; i++) { result += arguments[i] + separator; } return result; }

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

    // возвращает "red, orange, blue, " myConcat(", ", "red", "orange", "blue"); // возвращает "elephant; giraffe; lion; cheetah; " myConcat("; ", "elephant", "giraffe", "lion", "cheetah"); // возвращает "sage. basil. oregano. pepper. parsley. " myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");

    Т.к. arguments является псевдо-массивом, к нему применимы некоторые методы массивов, например, for .. in

    Function func() { for (value in arguments){ console.log(value); } } func(1, 2, 3); // 1 // 2 // 3

    Примечание: arguments является псевдо-массивом, но не массивом. Это псевдо-массив, в котором есть пронумерованные индексы и свойство length . Однако он не обладает всеми методами массивов.

    Оставшиеся параметры (Rest parameters)

    На введение стрелочных функций повлияли два фактора: более короткие функции и лексика this .

    Более короткие функции

    В некоторый функциональных паттернах приветствуется использование более коротких функций. Сравните:

    Var a = [ "Hydrogen", "Helium", "Lithium", "Beryllium" ]; var a2 = a.map(function(s) { return s.length; }); console.log(a2); // logs var a3 = a.map(s => s.length); console.log(a3); // logs

    Лексика this

    До стрелочных функций каждая новая функция определяла свое значение this (новый объект в случае конструктора, undefined в strict mode, контекстный объект, если функция вызвана как метод объекта, и т.д.). Это оказалось раздражающим с точки зрения объектно-орентированного стиля программирования.

    Function Person() { // Конструктор Person() определяет `this` как самого себя. this.age = 0; setInterval(function growUp() { // Без strict mode функция growUp() определяет `this` // как global object, который отличается от `this` // определенного конструктором Person(). this.age++; }, 1000); } var p = new Person();

    В ECMAScript 3/5 эта проблема была исправлена путем присвоения значения this переменной, которую можно было бы замкнуть.

    Function Person() { var self = this; // Некоторые выбирают `that` вместо `self`. // Выберите что-то одно и будьте последовательны. self.age = 0; setInterval(function growUp() { // The callback refers to the `self` variable of which // the value is the expected object. self.age++; }, 1000); }

    Смотрите также Function в Справочнике JavaScript для получения дополнительной информации по функции как объекту.

    9 ответов

    Существует несколько способов обработки событий с помощью HTML/DOM. Там нет реального права или неправильного пути, но разные способы полезны в разных ситуациях.

    1: Определяет его в HTML:

    2: добавьте его в свойство DOM для события в Javascript:

    //- Using a function pointer: document.getElementById("clickMe").onclick = doFunction; //- Using an anonymous function: document.getElementById("clickMe").onclick = function () { alert("hello!"); };

    3: И добавляет функцию обработчику событий, используя Javascript:

    Var el = document.getElementById("clickMe"); if (el.addEventListener) el.addEventListener("click", doFunction, false); else if (el.attachEvent) el.attachEvent("onclick", doFunction);

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

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

    Скорее всего, проблема находится где-то в вашей функции CapacityChart() . После посещения вашей ссылки и запуска вашего script запускается функция CapacityChart(), и открывается два всплывающих окна (один из них закрыт в соответствии с script). Если у вас есть следующая строка:

    CapacityWindow.document.write(s);

    Попробуйте вместо этого:

    CapacityWindow.document.open("text/html"); CapacityWindow.document.write(s); CapacityWindow.document.close();

    ИЗМЕНИТЬ
    Когда я увидел ваш код, я думал, что вы его пишете специально для IE. Как уже упоминалось, вам нужно будет заменить ссылки на document.all на document.getElementById . Тем не менее, после этого вам все равно придется исправлять script, поэтому я бы рекомендовал, чтобы он работал, по крайней мере, в IE, так как любые ошибки, которые вы делаете, изменяя код для работы с перекрестным браузером, могут вызвать еще большую путаницу. После его работы в IE будет легче узнать, работает ли он в других браузерах, пока вы обновляете код.

    Я бы сказал, что было бы лучше добавить javascript в ненавязчивую манеру...

    если вы используете jQuery, вы можете сделать что-то вроде:

    $(document).ready(function(){ $("#MyButton").click(function(){ CapacityChart(); }); });

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

    Проблема находится в функции CapacityCount . Я получаю эту ошибку в своей консоли на Firefox 3.5: "document.all is undefined" в строке 759 из bendelcorp.js.

    Похоже, что document.all - это только для IE и является нестандартным способом доступа к DOM. Если вы используете document.getElementById() , это должно сработать. Пример: document.getElementById("RUnits").value вместо document.all.Capacity.RUnits.value

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

    If(navigator.appName == "Netscape") { vesdiameter = document.forms["Volume"].elements["VesDiameter"].value; // more stuff snipped } else { vesdiameter = eval(document.all.Volume.VesDiameter.value); // more stuff snipped }

    Я нахожусь в Chrome, поэтому navigator.appName не будет Netscape . Поддерживает ли Chrome document.all ? Может быть, но опять же, возможно, нет. А как насчет других браузеров?

    Версия кода в ветке Netscape должна работать на любом браузере в обратном порядке до Netscape Navigator 2 с 1996 года, поэтому вы, вероятно, должны просто придерживаться этого... кроме того, что он не будет работать (или не гарантируется работа), потому что вы не указали атрибут name для элементов input , поэтому они не будут добавлены в массив формы elements как именованные элементы:

    Либо укажите им имя и используйте массив elements , либо (лучше) используйте

    Var vesdiameter = document.getElementById("VesDiameter").value;

    который будет работать на всех современных браузерах - не требуется разветвление. Чтобы быть в безопасности, замените это, обнюхивая версию браузера, большую или равную 4, с проверкой на поддержку getElementById:

    If (document.getElementById) { // NB: no brackets; we"re testing for existence of the method, not executing it // do stuff... }

    Вероятно, вы также захотите проверить свой ввод; что-то вроде

    Var vesdiameter = parseFloat(document.getElementById("VesDiameter").value); if (isNaN(vesdiameter)) { alert("Diameter should be numeric"); return; }

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

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

    Метод - это тоже функция, но, он принадлежит уже какому-то классу или объекту.

    Для того чтобы вызывать какой-то метод , необходимо сначала написать название объекта, потом через точку написать название метода. Исключением этого правила является вызов методов alert(), confirm() и prompt() объекта window. Их можно вызывать без того чтобы указать название объекта. С этими методами мы уже познакомились в этой статье .

    Также, в предыдущих статьях мы познакомились с методом вывода document.write() , который принадлежит объекту document.

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

    Синтаксис функции выглядит таким образом:


    Для примера создадим простую функцию, которая добавит переданный текст в абзац и выведет его. И ещё сделает его жирным и курсивным.

    Function writeText(text){ //Добавляем текст в абзаце и выводим его document.write("

    " + text + "

    "); } //Вызов созданной функции writeText("Здравствуйте!");

    Сохраняем документ и открываем его в браузере.


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

    Для чего нужны функции в программировании?

    Основным плюсом использования функции это сокращение размера исходного кода скрипта .

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

    //объявляем три массива var arr1 = ; var arr2 = ["b", 5, 9.2, "h", 8, 2]; var arr2 = ; for(var i = 0; i < arr1.length; i++){ document.write("

    Элемент массива arr1, с индексом " + i + " равен: "+ arr1[i] +"

    "); } for(var i = 0; i < arr2.length; i++){ document.write("

    Элемент массива arr2, с индексом " + i + " равен: "+ arr2[i] +"

    "); } for(var i = 0; i < arr3.length; i++){ document.write("

    Элемент массива arr3, с индексом " + i + " равен: "+ arr3[i] +"

    "); }

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

    Function printArr(arr){ for(var i = 0; i < arr.length; i++){ document.write("

    Элемент массива, с индексом " + i + " равен: "+ arr[i] +"

    "); } } //объявляем три массива var arr1 = ; var arr2 = ["b", 5, 9.2, "h", 8, 2]; var arr2 = ; //Вызываем созданную функцию, для перебора каждого массива printArr(arr1); printArr(arr2); printArr(arr3);

    Параметры функции

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

    Давайте создадим функцию без параметров , которая просто выведет на экран, классическую фразу "Hello world".

    Function helloWorld(){ document.write("Hello World"); } //Вызываем функцию без параметров, helloWorld helloWorld();

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

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

    Function summa(number1, number2 = 4){ document.write("

    Сумма чисел " + number1 + "(Первый параметр) и " + number2 + "(Второй параметр) равна: " + (number1 + number2) + "

    "); } //Вызываем функцию, которая, по умолчанию выведет результат сложения переданного числа, с цифрой 4. summa(5); // Результат: 9 //Если предадим и второй параметр, то функция выведет результат сложения чисел из обоих параметров. summa(5, 20); // Результат: 25

    Ещё допускается чтобы внутри какой-то функции можно было бы вызывать другую существующею функцию.

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

    Function summa(number1, number2 = 4){ writeText(number1 + number2); } //Вызываем функцию summa summa(5); // Результат: 9 summa(5, 20); // Результат: 25

    Функции которые возвращают какое-то значение

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

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

    Для того чтобы лучше понять о чем идёт речь, вспомним такие методы как prompt() и confirm(). Эти методы именно возвращают значение, полученное от пользователя, а не выводят его.

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

    Function lastElement(arr){ //Возвращаем последний элемент переданного массива return arr; } //Объявляем массив var otherArr = ["iphone", "asus", 2000, 9.8, "twix"]; //Вызываем созданную функцию lastElement и в качестве параметра передаем ей созданный массив otherArr var lastEl = lastElement(otherArr); //Выводим полученный последний элемент массива alert(lastEl);

    В результате мы получим слово ‘twix’, так как именно это слово и есть последний элемент массива otherArr.

    Метод alert() ничего не возвращает . То есть если мы попытаемся выводить переменную которая типа содержит результат вызова метода alert(), то увидим значение undefined . Это тоже самое как попытаться выводить значение пустой переменной.

    Для примера возьмём результат последнего вызова alert() из предыдущего примера, помещаем его в переменную resAlert и используя созданную нами функцию writeText, попытаемся вывести полученный результат.

    //Выводим полученный последний элемент массива var resAlert = alert(lastEl); var test; writeText(resAlert); //undefined writeText(test); //undefined

    Как видим в обоих случаях получили значение undefined.

    Глобальные и локальные переменные

    Глобальные переменные - это те переменные, которые объявлены за пределами функции. То есть все те переменные, которые не объявлены внутри самой функции, являются глобальными . Они видны (действительны) во всем документе.

    Локальные переменные - это те переменные, которые объявлены внутри самой функции . И они действительны только внутри данной функции. За её пределами, локальные переменные уже не будут работать.

    Локальные и глобальные переменные никак не связаны между собой.


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

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

    Вызываем функцию other(), и если теперь попробуем вывести значение переменной x, то в результате увидим цифру 4.

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

    Var x = 8; function increment(){ x++; } //Вызываем функцию increment() increment(); alert(x); //Результат: 9

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

    Var g = 100; function func(){ var g = 14; g *= 2; // Это тоже самое что g = g * 2 alert(g);//Результат: 28 } //Вызываем функцию. func(); alert(g);//Результат: 100

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

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

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

    Объявление и вызов функции JavaScript

    Синтаксис функции JavaScript выглядит следующим образом:

    function ""имя"" (""аргумент1"", ""аргумент2"", ""аргумент3"" ...) { ""операторы"" return ""значение"" }

    Имя определяет, как мы будем называть функцию при ее вызове. Аргументы задают значения, которые передаются функции для обработки. Раздел операторы представляет собой тело функции, которая выполняет обработку. Необязательный оператор return позволяет вернуть значение.

    В следующем примере показана функция, определяемая в разделе HTML-страницы и вызываемая в разделе :

    function sayHello() { alert("Привет!"); } sayHello();

    Передача аргументов в функцию

    В приведенном выше примере (script type text JavaScript function ) функции не передается никакие аргументы. Обычно функция предназначена для выполнения каких-либо действий с несколькими аргументами:

    Простой пример функции JavaScript function sayHello(day, month) { alert("Привет! Сегодня " + day + " " + month); } sayHello("24", "Июля"); sayHello ("1", "Августа"); sayHello ("24", "Мая");

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

    Возврат значения из функции

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

    Простой пример функции JavaScript var result = addValues(10, 20) document.write ("Результат = " + result);

    В приведенном выше примере мы передаем в функцию addValues значения 10 и 20 . Функция addValues складывает эти два значения и возвращает результат. Оператор return присваивает результат переменной result, которая затем используется для создания строки, выводимой на HTML-странице .

    Вызов JavaScript function может быть выполнен в разных местах. Например, не обязательно присваивать результат в качестве значения переменной. Можно использовать его непосредственно в качестве аргумента при вызове document.write .

    Важно отметить, что функция может возвращать только одно значение:

    Простой пример функции JavaScript function addValues(value1, value2) { return value1 + value2; } document.write ("Результат = " + addValues(10, 20)); JavaScript onclick function также могут использоваться в условных выражениях. Например: Простой пример функции JavaScript function addValues(value1, value2) { return value1 + value2; } if (addValues(10, 20) > 20) { document.write ("Результат > 20"); } else { document.write ("Результат < 20"); }

    Где размещать объявления функций

    Есть два места, в которых рекомендуется размещать объявления JavaScript function return: внутри раздела HTML-документа или во внешнем файле .js . Наиболее предпочтительным местом считается второй вариант, так как он обеспечивает наибольшую гибкость.

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

    Перевод статьи «Understanding JavaScript Functions » был подготовлен дружной командой проекта .

    Хорошо Плохо