Функции
В этой статье описаны функции Javascript на уровне языка: создание, параметры, приемы работы, замыкания и многое другое.
Существует 3 способа создать функцию. Основное отличие в результате их работы - в том, что именованная функция видна везде, а анонимная - только после объявления:
Именованные (FunctionDeclaration) |
Анонимные (FunctionExpression) |
function имя(параметры) {
...
} |
var имя = function(параметры) {
…
}
...
var имя = new Function(параметры, '...') |
Именованные функции доступны везде в области видимости |
Анонимные - доступны только с момента объявления. Синтаксис new Function используется редко, в основном для получения функции из текста, например, динамически загруженного с сервера в процессе выполнения скриптов. |
/* функция sum
определена ниже
*/
var a = sum(2,2)
function sum(x,y) {
return x+y
}
|
/* будет ошибка,
т.к sum еще не существует
*/
var a = sum(2,2)
var sum = function(x,y) {
return x+y
}
|
В javascript функции являются полноценными объектами встроенного класса Function. Именно поэтому их можно присваивать переменным, передавать и, конечно, у них есть свойства:
function f() {
...
}
f.test = 6
...
alert(f.test) // 6
Свойства функции доступны и внутри функции, так что их можно использовать как статические переменные.
Например,
function func() {
var funcObj = arguments.callee
funcObj.test++
alert(funcObj.test)
}
func.test = 1
func()
func()
В начале работы каждая функция создает внутри себя переменную arguments и присваивает arguments.callee ссылку на себя. Так что arguments.callee.test - свойство func.test , т.е статическая переменная test.
В примере нельзя было сделать присвоение:
var test = arguments.callee.test
test++
так как при этом операция ++ сработала бы на локальной переменной test , а не на свойстве test объекта функции.
Объект arguments также содержит все аргументы и может быть преобразован в массив (хотя им не является), об этом - ниже, в разделе про параметры.
Каждая функция, точнее даже каждый запуск функции задает свою индивидуальную область видимости.
Переменные можно объявлять в любом месте. Ключевое слово var задает переменную в текущей области видимости. Если его забыть, то переменная попадет в глобальный объект window . Возможны неожиданные пересечения с другими переменными окна, конфликты и глюки.
В отличие от ряда языков, блоки не задают отдельную область видимости. Без разницы - определена переменная внутри блока или вне его. Так что эти два фрагмента совершенно эквивалентны:
Заданная через var переменная видна везде в области видимости, даже до оператора var . Для примера сделаем функцию, которая будет менять переменную, var для которой находится ниже.
Например:
function a() {
z = 5 // поменяет z локально..
// .. т.к z объявлена через var
var z
}
// тест
delete z // очистим на всякий случай глобальную z
a()
alert(window.z) // => undefined, т.к z была изменена локально
Функции можно запускать с любым числом параметров.
Если функции передано меньше параметров, чем есть в определении, то отсутствующие считаются undefined .
Следующая функция возвращает время time , необходимое на преодоление дистанции distance с равномерной скоростью speed .
При первом запуске функция работает с аргументами distance=10 , speed=undefined . Обычно такая ситуация, если она поддерживается функцией, предусматривает значение по умолчанию:
// если speed - ложное значение(undefined, 0, false...) - подставить 10
speed = speed || 10
Оператор || в яваскрипт возвращает не true/false , а само значение (первое, которое приводится к true ).
Поэтому его используют для задания значений по умолчанию. В нашем вызове speed будет вычислено как undefined || 10 = 10 .
Поэтому результат будет 10/10 = 1 .
Второй запуск - стандартный.
Третий запуск задает несколько дополнительных аргументов. В функции не предусмотрена работа с дополнительными аргументами, поэтому они просто игнорируются.
Ну и в последнем случае аргументов вообще нет, поэтому distance = undefined , и имеем результат деления undefined/10 = NaN (Not-A-Number, произошла ошибка).
Непосредственно перед входом в тело функции, автоматически создается объект arguments , который содержит
- Аргументы вызова, начиная от нуля
- Длину в свойстве
length
- Ссылку на саму функцию в свойстве
callee
Например,
function func() {
for(var i=0;i<arguments.length;i++) {
alert("arguments["+i+"] = "+arguments[i])
}
}
func('a','b',true)
// выведет
// arguments[0] = a
// arguments[1] = b
// arguments[2] = true
Свойство arguments похоже на массив, т.к у него есть длина и числовые индексы. На самом деле arguments не принадлежит классу Array и не содержит его методов, таких как push , pop и других.
Если все же хочется воспользоваться этими методами, например, чтобы вызвать другую функцию с теми же аргументами, но кроме первого, можно создать из arguments настоящий массив:
var args = Array.prototype.slice.call(arguments)
// .. теперь args - настоящий массив аргументов ..
args.shift()
...
Вызвать функцию для массива аргументов можно при помощи apply :
var func = function(a,b) { alert(a+b) }
var arr = [1,2]
func.apply(null, arr) // => alert(3)
Функцию легко можно передавать в качестве аргумента другой функции.
Например, map берет функцию func , применяет ее к каждому элементу массива arr и возвращает получившийся массив:
var map = function(func, arr) {
var result = [ ]
for(var i=0; i<arr.length; i++) {
result[i] = func(arr[i])
}
return result
}
Пример использования:
map(run, [10, 20, 30]) // = [1,2,3]
Или можно создать анонимную функцию непосредственно в вызове map :
// анонимная функция утраивает числа
map( function (a) { return a*3 } , [1,2,3]) // = [3,6,9]
Бывают функции, аргументы которых сильно варьируются.
Например:
// можно указать только часть аргументов
// не указанные - вычисляются или берутся по умолчанию
function resize(toWidth, toHeight, saveProportions, animate) {
// значения по умолчанию
saveProportions = saveProportions || true
animate = animate || true
toHeight = toHeight || ...
}
Вызов с необязательными параметрами приходится делать так:
resize(100, null, null, true)
Чтобы избежать лишних null и сделать код более понятным, используют нечто вроде "keyword arguments", существующих в Python и Ruby. Для этого много параметров пакуют в единый объект:
function resize(setup) {
// значения по умолчанию
var saveProportions = setup.saveProportions || true
var animate = setup.animate || true
var toHeight = setup.toHeight || ...
}
Вызов теперь делается гораздо проще:
var setup = {toWidth: 100, animate: true}
resize(setup)
// или
resize({toWidth: 100, animate: true})
Так - куда понятнее. А если параметров больше 5, то вообще - единственный нормальный способ.
Кроме того, с объектом можно удобнее делать последовательности вызовов вроде:
var setup = {toWidth: 100, animate: true, saveProportions: false}
resize(setup)
setup.toWidth = 200
resize(setup)
|
Конечно мне всё описанное в статье уже известно, но материал очень полезный.
Жаль, что в то время, когда я только начинал изучать программирование и JavaScript, не было таких статей...
Очень внятно и полезно - СПАСИБО!
Да, статьи у тебя, Илья, как всегда, полезны. Доходчиво написано, особенно для новичков.
Есть маленькое уточнение:
> Именованные (FunctionDeclaration)
не каждая именованная функция является declaration'ом:
Для новичков..?
Вот я новичок. И я ничерта не понял) После второго абзаца мозг расплавился.
Хотя я пытался выяснить простую вещь: почему в функцию передается число и не передается текст? Но этого тут я так и не нашел =\
В функцию в качестве аргумента элементарно передать как числовую, так и строковую переменную.
Спасибо огромное! Очень долго искал вот это для своей JS библиотеки:
Поддержу, отличный метод
Отличная статья
А как все таки задавать значения параметров по умолчанию?
Только уже в самом теле функции?
Да, только в теле функции
Блин, а я как не разбиралась в Яве, так и не разбираюсь...Надо учиться
Касательно :
Я верю,что так и будет, но не понимаю здесь преобразование типов. Я так понимаю, что В правой части speed должно преобразовываться к Boolean и если он true, то второй опреанда 10 не вычисляется, но при этом и левой части должно присвоиться значение типа Boolean, а не того типа , которое имеет speed на входе в функцию. В чем я ошибаюсь и почему ?
Оператор
||
в яваскрипт возвращает неtrue/false
, а само значение (первое, которое приводится к true).или последнее, которое приводится к false
Объекты , передаются в функцию по ссылке, а как передать в функцию по ссылке параметры примитивных типов (Undefined , Null, Boolean, String, Number ), чтобы можно было их изменить в функции ?
Никак. Элементарные значения не передаются по ссылке, только объекты, к которым также относятся массивы, даты и т.п.
Здесь javascript ведет себя так же, как, например, java/php5
А вот и неправда, можно привести их к object и передать в функцию, тогда они будут переданы по ссылке
И тогда они не будут примитивными. Отличная логика.
PHP5 (или даже PHP4, хотя не уверен, не писал на нём чисто) прекрасно передает переменные по ссылке, но по умолчанию по ссылке передаются только объекты и ресурсы (не массивы), так что сравнение как минимум не корректное.
Вот черт, только сейчас обнаружил, что переменные в функции могут передаваться только по значению. Хоть бы кто написал где .Все время по привычке закрывал формальные параметры локальными перменными.
Насчёт заклинания:
Хотелось бы иметь либо подробное разъяснение, либо ссылку на место где можно читать про соответствующую магию.
Я так полагаю второе предпочтительнее, т.к. это выходит за рамки статьи.
Функция slice(), которая используется для преобразования возвращает новый массив со всеми значениями, переданными в функцию в качестве аргумента.
Вопрос по поводу проставления булевых значений по умолчанию в этом куске кода:
// можно указать только часть аргументов
// не указанные - вычисляются или берутся по умолчанию
function resize(toWidth, toHeight, saveProportions, animate) {
// значения по умолчанию
saveProportions = saveProportions || true
animate = animate || true
toHeight = toHeight || ...
}
Что будет если вызвать эту функцию со следующими параметрами?
resize(100, null, false, true)
Казалось бы, если учесть следующее утверждение:
// если speed - ложное значение(undefined, 0, false...) - подставить 10
speed = speed || 10
то значение параметра saveProportions будет вычислено как false || true == true, хотя в данном случае мы хотели, чтобы saveProportions равнялось false.
Я правильно понимаю?
Да, Ты понимаешь правильно
пиши так:
function myFunc(s)
{
if (typeof s == "undefined") s = "default value for s";
alert(s);
};
Не понятно про имена функций при вызове по ссылке. Мы можем сослатся на функцию вот так:
Тоесть мы переменную myFunc фактически приравниваем к функции.
Но мочему тогда нельзя сделать вот так?
Вовсяком случае у меня этот код не работает.
Как быть если имя нужной функции я вычисляю и результат помещаю в строковую переменную? Тоесть строковая переменная содержит имя нужной мне функции. При попытке вызова как напрямую, так и через someVar.call() / someVar.apply() - получаю ошибку. Не ужели только через eval(someVar+"()") ?
Привет. Присвоение значения переменной надо делать без кавычек:
var someVar = myFunc;
Спасибо за ответ, но.... :-)
Суть именно в том, что в кавычках вычесляется имя функции, которую нужно запустить. Кавычки тут не зря. К примеру:
;
Это просто пример, но суть думаю понятна - имя функции вычесляется динамично.
Как в таком случае можно запустить "вычесленную" функцию? Пока я использу eval(), но есть ли более красивое решение?
Только если записывать ф-ию в хеш (или объявлять ее глобально, что почти тоже самое: она попадет в объект window).
попробуй new Function для этого случая
Можно так сделать:
пример к "Сворачивание параметров в объект" не очень хороший честно говоря.
вполне можно просто вызвать resize(100) и все оставшиеся аргументы возьмутся по умолчанию.
А сворачивать аргументы в объект имеет смысл если часто нуно изменять например 3 и пятый аргумент на отличные от умалчиваемых.
Нигде не могу найти, что означает такая запись:
Может это вызов функции, которую вернёт внутренний function?
Только зачем так...
функция без имени создаётся и сразу вызывается.
Полезно для упрятывания от посторонних локальных переменных, и ещё из неё можно выйти через return - чего нельзя сделать, если код функции записать непосредственно.
это анониманая функция.
если сделать var f = function(){}; - это тоже создаст анонимную функцию но присврет сылку на нее локальной переменой var. () после функции - запуск ее на выполнение.
nта же констукция коорая расматриваеться создает свою область видимости (скоуп), что позволяет (как и сказал предыдущий оратор) использовать переменные не опасаясь что где-то в коде выше уже кто-то их использует перменнные с таким же именем - вообще это пример хорошего тона.
Здравствуйте.
Скажите пожалуйста сколько значений может содержать переменная в функции в javascript?
Вот пример скрипта:
function dateString (date, string) {
var year=date.getFullYear();
var month=date.getMonth();
string = string.replace(/%Y/g, year);
string = string.replace(/%y/g, month);
return string;
}
......................
var today = new Date();
var message = dateString(today, 'Today is %Y, %y');
document.write(message);
Мне непонятно почему и как переменная string возвращает два значения (согласно условиям двух регулярных выражений). Ведь насколько мне известно с помощью return функция может возвращать лишь одно значение.
С уважением Василий.
P.S. Прошу не судить строго, возможно вопрос покажется чересчур наивным, но на JavaScript подсел не так давно и это уже начинает сильно увлекать, интересный язык.
Дело в том, что функция может возвращать объекты в которых множество переменных, например a.val1=1; a.val2=1; и тд
А объект то один
Про область видимости хотелось бы узнать где она тогда начинается и заканчивается для var, какая же она локальная если до нее можно из-за пределов блока дотянуться ?
Поддерживаю вопрос. Совершенно не раскрыт.
Вот кусок кода
Мне непонятно, например, каким образом анонимная функция
получает значение $dialog при вызове по клику.
Это обычная перемення которая выше по коду обявлена
var $dialog = $('
').append($loading.clone());
Наишите про return. Для чего оно? Когда используется, а когда нет?
Не могу понять что тут происходит: Array.prototype.slice.call(arguments)
Я знаю что Array.prototype.метод(свойство) = реализация(значение) добавление метода(свойства) к статическому объекту Array. Slice() применяется к массивам для формирования выборки текущего массива. Call применяется к объекту функции для ее вызова. А вот что происходит в Array.prototype.slice.call(arguments) не могу понять???
arguments конвертируется в полноценный массив.
Здравствуйте! Хотел бы немного раскрыть тему:
""""""""""""""""""""""""""""""""""""
В примере нельзя было сделать присвоение:
var test = arguments.callee.test
test++
так как при этом операция ++ сработала бы на локальной переменной test, а не на свойстве test объекта функции
""""""""""""""""""""""""""""""""""""
Как я понял, это происходит из-за того, что даже если назначить переменной arguments.callee.test ссылку на объект, то далее при любых операциях с ним, например test++, эта переменная test превратится в значение, то есть простой number (в данном случае), а не в наследник object-а. Правьте, если не прав:)
для простых типов справедливо следующее правило:
но помимо простых типов есть объекты и массивы - для них правило другое:
это происходит потому, что объекты и массивы передаются по ссылке а не по значению
соответственно если в вашем случае надо делать так:
можно как нибудь проще?
Прикольно так то:-D Можно сделать подобие ООП, например, вот код:
//////////////////////////////////////////////////////////
function simpleFunction() {
// Создали машинку
var car = createCar();
// Указали, что это грузовик
car.type = "грузовик";
// Поехали!
car.doRun();
}
function createCar() {
// Типа объявление переменной
var type = "";
// Типа объявление метода
var doRun = function() {
alert("Я " + car.type + " и я поехал!");
}
// Типа подобие конструктора
var car = { type: type, doRun: doRun };
return car;
}
//////////////////////////////////////////////////////////
Ну это просто так мысли вслух:)
Замечания к своему же коду:
1. Инкапсулирование - можно через getter/setter.
2. Полиморфизм - можно сделать, тока муторно (по сравнению с чисто ООП языками).
3. Ну и там всякие области видиомости тож непонятно как.
А JavaScript не чисто ООП язык О_о?????
В нём даже функции и простые (например string) переменные - объекты, комментарий вообще мимо по-моему.
То что написано - лишь жалкое подобие класса.
ООП в JS не такое, как, скажем, в Java / C++ / PHP.
В JS, например, нет классов (и, следственно, интерфейсов), специфическое наследование. Подробнее тут.
Подскажите, плиз, на что в данной функции будет ссылаться this? а то я только начала разбираться с JS...
function addHandler() {
for (i = 0; i < CascadingDropdowns.length; i++) {
if(CascadingDropdowns[i].parentLookup.isDropDown) {
CascadingDropdowns[i].parentLookup.Object.onchange = function() { FilterChooicesForMyChild(this); }
}
else {
CascadingDropdowns[i].parentLookup.Opthid.onpropertychange = function() { FilterChooicesForMyChild(this); }
}
alert(CascadingDropdowns[i]);
}
setupComplete = true;
}
Внутри обработчиков событий this будет ссылаться на объект, к которому эти обработчики присоединены.
При добавлении через attachEvent в MSIE это не так.
-- В отличие от ряда языков, блоки не задают отдельную область видимости.
блоки это {} ? или что то другое ? а то тогда не понятно что же задает область видимости?
Я так понял, что область видимости задают функции. А если просто {} - то нет.
Может я и неправильно понял...
Помогите пожалуйста:
Как на событие повесить выполнение функции с передачей в нее параметров?
$("area").bind("mouseover", on (this)); ------ Не работает
function on (param) {
...
}
если jQuery используется, то так:
Спасибо!
"Заданная через var переменная видна везде в области видимости, даже до оператора var."
Это как так?
То есть так: по сути фраза правильная, но требует пояснений, что undefined - это значит видна, но не имеет определенного значения.
Здравствуйте!
Встречаю иногда вот такую конструкцию:
var somefunc=function(){
var id = 'tt';
...
return{
show:function(){
...
},
hide:function(){
...
}
};
}();
Используется она вот так:
somefunc.show();
Что это, зачем ? Почему просто не использовать объект ?
Почему после завершающей фигурной скобки стоит () ?
Где про это можно почитать ?
Почему не используется объект - это вопрос тем, кто писал код. Скорее всего здесь функция, чтобы передать доп. параметры.
А () - это оператор вызова функции. Соответственно, всё это выражение возвращает объект, который присваивается переменной somefunc, а потом происходит обращение к его свойству.
Это же замыкания - для того чтобы в функциях somefunc.show() и somefunc.hide() была определена переменная id не глобальная
недавно чисто интуитивно для статик переменной использовал this, почитал статью дошел до места http://javascript.ru/basic/functions#funkcii---obekty, и понял - что что то я не то сделал... чем грозит использование this в подобных целях?
екзампл к предыдущему комменту
дошел в чем проблема, глобальная видимость этой переменной, извините за спам
Подскажите, после отработки функции она находится в памяти и может мешать другим функциям? И как можно принудительно выгрузить из памяти функцию?
Вообще, я знаю, что в js нет управления памятью (слишком жирно было бы), но сборка мусора есть. Поэтому функция может быть выгружена из памяти, если на нее будут удалены все ссылки. Пример:
Так.. объекты и примитивные типы передаются в функцию только по значению. Никакой передачи по ссылке объектов не существует.Автор, поправь статью. Эта проблема затронута в книге Professional JavaScript for Web Developers.
Насчет Вызывание функцию для массива аргументов можно при помощи apply:
var func = function(a,b) { alert(a+b) }
var arr = [1,2]
func.apply(null, arr) // => alert(3)
Почему в примере аргумент функции null? и как этот пример выводит 3? Можете разъяснит?
Спасибо.
На сколько я знаю, дело в функции apply. Первым параметром для нее является контекст обьекта, который в данном случае может быть null ( будем использован глобальный контекст ). А вторым аргументом идет массив параметров для той же функции func. В результате этот массив и интерпретируется как а и b.
А как в качестве аргумента функции JS передать массив сформированный в php скрипте.
Если в теле функции писать просто arrayArg[0] и т.д. то это не работает
Народ подскажите плиз, как подключить ява-скрипт на странице, путем нажатия кнопки юзером на сайте?
В статье ошибка:
{
var i=0;
}
эквивалентно !!! ошибка
var i=0;
{
}
надо
var i;
{
i=0;
}
Я бы не назвал это так громко - ошибкой . Это вообще не ошибка - показано, что переменная видна как в скобках, так и за в обоих случаях, независимо в каком месте она объявлена, что и требовалось.
чем отличаются
( function(){ } )() - круглые скобки снаружи
от
( function(){ }() ) - внутри
ничем
Привет!
Почему Я не могу получить значение return в переменную aname?
Выводит undefined.
А как получить значение return?
a.status не 200
Ваш return возвращает значение НЕ из функции aajax() (как Вы, должно быть, предполагали), а из анонимной функции, присвоенной методу onreadystatechange.
а функция aajax() вообще не возвращает значения.
Подскажите а можно ли переменной присвоить картинку а потом вызывать эту картинку через переменную, если можно то как.
люди подскажите практический пример использования callee, если можно не применительно к web. я "написал"
function test()
{
var funcObj = arguments.callee;
funcObj.t = arguments.length; // определяем свойство t
return funcObj.t;
}
v = test("xcd", 34, false);
WScript.Echo("Функция была вызвана с " + v + " аргументами");
только непонятно как/в каком случае полезно использовать callee???
Очень подробное описание с примерами
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_...
Доброго дня! Допоможіть будь ласка. Є два діва з текстом, колір тексту ми не знаємо. при кожному натисканні на кнопку кольри текстів міняються між собою. Потрібно описати JS.
Переведите на русский.
var имя = function(параметры) {
…
}
это не анонимные функции, анонимные это function(параметры) {…}
Почему отображает undefined?:
Было бы удобно далее делать так:
Не будет работать с undefined.
Есть функция, которая находит html элементы, берет их значение, меняет, заменяет значение. Когда происходит обновление странички ajax'ом, функция видит только старые элементы - новых просто нет. Как сделать так, чтобы функция корректо работала с новыми элементами?
Предполагаю что дело в том, что html элементы находятся функцией единожды - при ее создании. Значит мне нужно переобъявлять функцию?
Прошу js-гуру помочь!
В firefox, из HTML-странички, вызвал testSum из кода:
var sum = function(a,b) {
alert(a+b)
}
var testSum = function() {
var arr1 = [1,2,3]
var arr2 = [4,5,6]
var arr3 = [7,8,9]
sum.apply(arr1,arr2,arr3)
Получил результат 7, т.е. функция sum получила два первых параметра из второго массива. Пробовал с другими количествами массивов и параметров, с разными длинами массивов. Понимания как работает apply это не прибавило. Не могли бы Вы прояснить как работает apply, если не трудно?
Заранее благодарен.
котофей,
"метод" apply обрабатывает два параметра
- контекст выполнения (англ. scope);
- аргументы (параметр должен быть массивом);
Остальные параметры игнорируются. Для иллюстрации изменим Ваш пример.
извините, не 7, а 9, конечно. 4+5 = 9.
Что эффективнее (быстрее): использовать в теле функции глобальную переменную (как неизменяемую величину) или эту глобальную передать функции как параметр?
Помогите понять как расшифровать такую запись
function myhash(b,e,f){(f='')||(e=window)&&(b||(b=e[18])));
f+=b;return f}
Интересует вот это - (f='')||(e=window)&&(b||(b=e[18])));
Что здесь объявляется или какие условия что выполняют?
>встроенного класса Function
- в JavaScript нет классов - это язык прототипный)
Подскажите как сделать чтоб звук воспроизводился сразу при попытке закрытия окна?
ЗВук воспроизводиться только после закрытия этого окна(
В объявлении function f_8(gold,silver,cash,stock,commercial,future_income,debts) много переменных.
Когда переменных больше двух, то нужно писать вот так
- объвляем function f_8(props)
- вызываем так:
f_8 ({
gold: 1,
silver: 1,
cash: 1,
stock: 1,
commercial: 1,
future_income: 1,
debts: 1,
})
- внутри используем их так:
props.gold, props.siler и так далее.
Пожалуйста можете это мне на примере показать, я вообще не врубаюсь, что мне говорит этот человек
Очень подробно четко красиво очень рад то что я нашел этот сайт спасибо Админам!
В статье "В javascript функции являются полноценными объектами" - не корректно. Объект не копируется при присваивании переменной.