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

  0    0 
25.11.2016 | kievol | 2804

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


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

    Создаем 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 Если вы…

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

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

  • Массовая замена значений в БД mysql средствами PHPMyAdmin
    Массовая замена значений в БД mysql средствами PHPMyAdmin

    Иногда требуется массово заменить значения в ячейке таблицы базы данных mysql. Допустим стоит задача: одним запросом во всей таблице базы данных поменять запись «значение 1» на  «значение2» . Как это сделать разберём ниже. Заходим в интерфейс phpMyAdmin.  Допустим, у нас есть таблица «yuts_catalog»,в ней поле «leader», и значения в ячейке этого поля «0″, которое…

  • 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 и выделяем строку. Справа нажимаем "Добавить…

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

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

  • Дерев'яні іграшки для вашої дитини
    Дерев'яні іграшки для вашої дитини

    У цій статті ми з вами розглянемо користь та шкоду, які можуть нести дерев'яні іграшки вашій дитині. Зараз це один із недешевих видів іграшок для вашої дитини. Тому що зроблені вони з природного матеріалу. Вони несуть позитивну енергетику щодо безпечні. Які плюси мають…
    Блогер: amd2015

  • Подагра. Все що ми знаємо про подагру.
    Подагра. Все що ми знаємо про подагру.

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

  • Низька самооцінка. Як повірити в свої сили
    Низька самооцінка. Як повірити в свої сили

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

  • Ігроманія: причини та наслідки
    Ігроманія: причини та наслідки

    У зв'язку зі швидким розвитком технологічного прогресу, нині людство страждає від нової «чуми» - хвороби ХХІ століття, ігроманії. Що дивно, від хворобливої ​​залежності від гри страждають не лише діти та підлітки, а й безліч дорослих. Причини: порушення…
    Блогер: amd2015

  • Як відволікти дитину від смартфона
    Як відволікти дитину від смартфона

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


Комментарии

29 + 85 =