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

  0    0 
25.11.2016 | kievol | 2781

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

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

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

function makeArray(arg1, arg2){
  return [ this, 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.

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

<input type="button" value="Button 1" id="btn1" />
<input type="button" value="Button 2" id="btn2" />
<input type="button" value="Button 3" id="btn3" onclick="buttonClicked();" />

<script type="text/javascript">
function buttonClicked(){
  var text = (this === window) ? 'window' : this.id;
  alert( text );
}
var button1 = document.getElementById('btn1');
var button2 = document.getElementById('btn2');

button1.onclick = buttonClicked;
button2.onclick = function(){ buttonClicked(); };
script>


Щелчок по первой кнопке покажет сообщение «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, поэтому имеет смысл предупреждать их возникновение заранее.


  • Параметры вставки youtube видео на сайт и секреты
    Параметры вставки youtube видео на сайт и секреты

    Youtube.com — самый известный видео хостинг, миллионы уже загруженных видео-роликов.Вы захотели добавить видео к себе на страницу. <iframewidth="560"height="315"src="//www.youtube.com/embed/2GbSpPxzDeY"frameborder="0"allowfullscreen> Но чтобы немного изменить вид и действие плеера, есть несколько параметров.Параметры добавляются в src после знака вопроса (?), а все последующие – через амперсанд & или…

  • Автоматический перезапуск программы после закрытия
    Автоматический перезапуск программы после закрытия

    Создаем bat файл со следующим содержимым @echo offecho Starting process...echo.:EnterNameSet /p Process="Enter process name:"IF NOT EXIST %Process% GOTO EnterName:begintitle Process %Process% controltasklist | findstr %Process%if errorlevel 1 goto NoProcessecho Result: Process rungoto Done:NoProcess%Process%echo Result: Process %Process% stop %time%:Doneecho.goto beginpauseexit   Файл bat данного содержания нужно поместить в папку с вашим исполняемым файлом. При запуске он спросит имя файла - нужно ввсети в формате Name.exe Если вы…

  • SSL сертификат в Open Server
    SSL сертификат в Open Server

    В разработке, я постоянно использую локальный Open Server (OSpanel) и нахожу его очень удобным из-за его гибких настроек и обилия различных модулей. Однако, в каждой новой версии остается одна проблема — отсутствие настроек SSL сертификатов. Поэтому далее я покажу как решить эту проблему… SSL в Open Server — в чем проблема? В этом и заключается все, что как таковой проблемы нет, но есть…

  • полезные PHP скрипты
    полезные PHP скрипты

    Не так уж конечно и давно, но занимался, в серьёз, PHP программированием, но потом как то забросил. А вот сейчас порой нужно что ни будь дописать, но программирование, как и иностранный язык, без повторений можно всё забыть, а вспоминать — время. Поэтому решил написать не большие, но полезные примеры на php, дабы не забыть и воспользоваться, когда будет нужно.1. Отправка E-mail…

  • IIS и 1С ошибки: Обнаружено потенциально опасное значение Request.Path или ошибка 500
    IIS и 1С ошибки: Обнаружено потенциально опасное значение Request.Path или ошибка 500

    Ошибка примерно такая:[HttpException (0x80004005): Обнаружено потенциально опасное значение Request.Path, полученное от клиента (:).] System.Web.HttpRequest.ValidateInputIfRequiredByConfig() +9914812 System.Web.PipelineStepManager.ValidateHelper(HttpContext context) +53Алгоритм следующий:  Открываем IIS. Открываем наш сайт-публикацию в браузере. Идем в сопоставления обработчиков. Ищем ISAPI-dll и выделяем строку. Справа нажимаем "Добавить…

  • Прием на работу: какие проблему могут повлиять на результат?
    Прием на работу: какие проблему могут повлиять на результат?

    На рынке труда главной задачей соискателя является произвести достойное впечатление. Помехой этому могут быть любые мелочи, так как HR менеджеры стараются подобрать для работодателя безупречного работника через сайт: http://uajobs.com.ua/rus/ . Тем более, если эти мелочи связаны со…
    Блогер: amd2015

  • Чи допомагають продукти з негативною калорійністю схуднути?
    Чи допомагають продукти з негативною калорійністю схуднути?

    Продукти з негативною калорійністю існують?Для початку необхідно зрозуміти, що ж собою представляють продукти з негативною калорійністю. Все дуже просто: ми з’їдаємо продукт, в якому мало калорій. А на його перетравлення наш організм витрачає більше енергії, ніж у…
    Блогер: amd2015

  • Три звички для підвищення самооцінки
    Три звички для підвищення самооцінки

     Сьогодні мені хочеться не просто поговорити, а поділитися з вами чимось практичним. Назвемо це звичками для любові до себе. Якщо ви зробите ці звички частиною свого життя, то, точно, побачите значні зміни на краще.   Перша звичка для підвищення самооцінки Дбайте…
    Блогер: amd2015

  • Як тренувати руки вдома. Комплекс вправ з гантелями
    Як тренувати руки вдома. Комплекс вправ з гантелями

    Так як для тренування рук достатньо гантелей, то біцепс та трицепс можна качати вдома. Головне, приділити увагу м’язам грудей, плечей та трапецій. Для цього потрібно виконувати комплекс вправ з гантелями.  Їх прокачування сприяє розвитку верхньої частини тіла, роблячи…
    Блогер: amd2015

  • Корінь лепехи його історія та лікувальні властивості.
    Корінь лепехи його історія та лікувальні властивості.

    Аїр - це трав'яниста рослина. У народі його називають татарське зілля, болотник, очерет. Ще в народі його називають аїр від тисячі хвороб. Росте на болотистих місцях водоймищах. Має довге мечоподібне листя до одного метра. Є історична гіпотеза про те, як потрапила ця рослина…
    Блогер: amd2015


Комментарии

17 + 78 =