Функции

Оператор typeof

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

У него есть две синтаксические формы:

  1. Синтаксис оператора: .
  2. Синтаксис функции: .

Другими словами, он работает со скобками или без скобок. Результат одинаковый.

Вызов возвращает строку с именем типа:

Последние три строки нуждаются в пояснении:

  1. — это встроенный объект, который предоставляет математические операции и константы. Мы рассмотрим его подробнее в главе Числа. Здесь он служит лишь примером объекта.
  2. Результатом вызова является . Это официально признанная ошибка в , ведущая начало с времён создания JavaScript и сохранённая для совместимости. Конечно, не является объектом. Это специальное значение с отдельным типом.
  3. Вызов возвращает , потому что является функцией. Мы изучим функции в следующих главах, где заодно увидим, что в JavaScript нет специального типа «функция». Функции относятся к объектному типу. Но обрабатывает их особым образом, возвращая . Так тоже повелось от создания JavaScript. Формально это неверно, но может быть удобным на практике.

Я знал ответ, это же просто

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

Итак, значит функция в коде блока выше является анонимной:

const myFunc = function() { };

А что, если я тебе скажу, что ты можешь обратится к свойству name, и получить конкретное значение?

myFunc.name // "myFunc"

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

Квадратные скобки

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

JavaScript видит, что мы обращаемся к свойству , а затем идёт непонятное слово . В итоге синтаксическая ошибка.

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

Для таких случаев существует альтернативный способ доступа к свойствам через квадратные скобки. Такой способ сработает с любым именем свойства:

Сейчас всё в порядке

Обратите внимание, что строка в квадратных скобках заключена в кавычки (подойдёт любой тип кавычек)

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

Здесь переменная может быть вычислена во время выполнения кода или зависеть от пользовательского ввода. После этого мы используем её для доступа к свойству. Это даёт нам большую гибкость.

Пример:

Запись «через точку» такого не позволяет:

Мы можем использовать квадратные скобки в литеральной нотации для создания вычисляемого свойства.

Пример:

Смысл вычисляемого свойства прост: запись означает, что имя свойства необходимо взять из переменной .

И если посетитель введёт слово , то в объекте теперь будет лежать свойство .

По сути, пример выше работает так же, как и следующий пример:

…Но первый пример выглядит лаконичнее.

Мы можем использовать и более сложные выражения в квадратных скобках:

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

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

10) addEvent()

Несомненно, важнейший инструмент в управлении событиями! Вне зависимости от того, какой версией вы пользуетесь и кем она написана, она делает то, что написано у неё в названии: присоединяет к элементу обработчик события.

function addEvent(elem, evType, fn) {
	if (elem.addEventListener) {
		elem.addEventListener(evType, fn, false);
	}
	else if (elem.attachEvent) {
		elem.attachEvent('on' + evType, fn)
	}
	else {
		elem = fn
	}
}

Этот код обладает двумя достоинствами — он простой и кросс-браузерный.

Основной его недостаток — в том, он не передает в обработчик для IE. Точнее, этого не делает .

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

elem.attachEvent("on"+evType, function() { fn.apply(elem) })

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

Существует два варианта обхода проблемы:

  1. Возвращать функцию, использованную для назначения обработчика:
    function addEvent(elem, evType, fn) {
    	if (elem.addEventListener) {
    		elem.addEventListener(evType, fn, false)
                    return fn
    	}
    
            iefn = function() { fn.call(elem) } 
            elem.attachEvent('on' + evType, iefn)
    	return iefn
    }
    
    function removeEvent(elem, evType, fn) {
    	if (elem.addEventListener) {
    		elem.removeEventListener(evType, fn, false)
                    return
    	}
     
            elem.detachEvent('on' + evType, fn)
    }
    

    Используется так:

    function handler() { 
        alert(this) 
    }
    var fn = addEvent(elem, "click", handler)
    ...
    removeEvent(elem, "click", fn)
    
  2. Можно не использовать в обработчике события вообще, а передавать элемент через замыкание:

    function handler() { 
       // используем не this, а переменную, ссылающуюся на элемент
        alert(*!*elem*/!*) 
    }
    ...
    

В качестве альтернативы и для примера более серьезной библиотеки обработки событий вы можете рассмотреть статью Кросс-браузерное добавление и обработка событий.

Остаточные параметры (…)

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

Например:

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

Остаточные параметры могут быть обозначены через три точки . Буквально это значит: «собери оставшиеся параметры и положи их в массив».

Например, соберём все аргументы в массив :

Мы можем положить первые несколько параметров в переменные, а остальные – собрать в массив.

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

Остаточные параметры должны располагаться в конце

Остаточные параметры собирают все остальные аргументы, поэтому бессмысленно писать что-либо после них. Это вызовет ошибку:

должен всегда быть последним.

JavaScript Функции

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

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

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

Придумывайте правильные имена

В разговоре о переменных необходимо упомянуть, что есть ещё одна чрезвычайно важная вещь.

Название переменной должно иметь ясный и понятный смысл, говорить о том, какие данные в ней хранятся.

Именование переменных – это один из самых важных и сложных навыков в программировании. Быстрый взгляд на имена переменных может показать, какой код был написан новичком, а какой – опытным разработчиком.

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

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

Несколько хороших правил:

  • Используйте легко читаемые имена, такие как или .
  • Избегайте использования аббревиатур или коротких имён, таких как , , , за исключением тех случаев, когда вы точно знаете, что так нужно.
  • Делайте имена максимально описательными и лаконичными. Примеры плохих имён: и . Такие имена ничего не говорят. Их можно использовать только в том случае, если из контекста кода очевидно, какие данные хранит переменная.
  • Договоритесь с вашей командой об используемых терминах. Если посетитель сайта называется «user», тогда мы должны называть связанные с ним переменные или , а не, к примеру, или .

Звучит просто? Действительно, это так, но на практике для создания описательных и кратких имён переменных зачастую требуется подумать. Действуйте.

Повторно использовать или создавать новую переменную?

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

В результате их переменные похожи на коробки, в которые люди бросают разные предметы, не меняя на них этикетки. Что сейчас находится внутри коробки? Кто знает? Нам необходимо подойти поближе и проверить.

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

Дополнительная переменная – это добро, а не зло.

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

Function Expressions

A JavaScript function can also be defined using an expression.

A function expression can be stored in a variable:

Example

var x = function (a, b) {return a * b};

After a function expression has been stored in a variable, the variable can
be used as a function:

Example

var x = function (a, b) {return a * b};
var z = x(4, 3);

The function above is actually an anonymous function (a function without a
name).

Functions stored in variables do not need function names. They are always
invoked (called) using the variable name.

The function above ends with a semicolon because it is a part of an executable statement.

Arrow Functions

Arrow functions allows a short syntax for writing function expressions.

You don’t need the keyword, the keyword, and the
curly brackets.

// ES5
var x = function(x, y) {
 
return x * y;
}
// ES6
const x = (x, y) => x * y;

Arrow functions do not have their own .
They are not well suited for defining object methods.

Arrow functions are not hoisted. They must be defined before they are used.

Using
is safer than using , because a function expression is
always constant value.

You can only omit the keyword and the curly brackets if the function is a single statement.
Because of this, it might be a good habit to always keep them:

Литералы и свойства

При использовании литерального синтаксиса мы сразу можем поместить в объект несколько свойств в виде пар «ключ: значение»:

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

В объекте сейчас находятся два свойства:

  1. Первое свойство с именем и значением .
  2. Второе свойство с именем и значением .

Можно сказать, что наш объект – это ящик с двумя папками, подписанными «name» и «age».

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

Для обращения к свойствам используется запись «через точку»:

Значение может быть любого типа. Давайте добавим свойство с логическим значением:

Для удаления свойства мы можем использовать оператор :

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

Последнее свойство объекта может заканчиваться запятой:

Это называется «висячая запятая». Такой подход упрощает добавление, удаление и перемещение свойств, так как все строки объекта становятся одинаковыми.

Объект, объявленный как константа, может быть изменён

Объект, объявленный через , может быть изменён.

Например:

Может показаться, что строка должна вызвать ошибку, но нет, здесь всё в порядке. Дело в том, что объявление защищает от изменений только саму переменную , а не её содержимое.

Определение выдаст ошибку только если мы присвоим переменной другое значение: .

Есть ещё один способ сделать константами свойства объекта, который мы рассмотрим в главе Флаги и дескрипторы свойств.

Синтаксис

Синтаксис для объявления функции:

Функция создаётся с заданными аргументами и телом .

Это проще понять на конкретном примере. Здесь объявлена функция с двумя аргументами:

А вот функция без аргументов, в этом случае достаточно указать только тело:

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

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

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

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

Параметры, которые можно вызвать функцией

При вызове function ей можно отправить данные для обработки. Например, нижеследующий код выведет 2 сообщения:

 function showMessage(from, text) { // параметры from, text
 from = "** " + from + " **"; // здесь вставляем сложный код оформления
 alert(from + ': ' + text);
}
showMessage('Петя', 'Привет!');
showMessage('Петя', 'Как дела?');

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

showMessage("Петя");

Вызов функции как метода

В JavaScript можно определить функции как методы объектов.

В следующем примере создается объект (myObject) с двумя свойствами (firstName и
lastName) и метод (fullName):

Пример

var myObject = {
  firstName:»Андрей»,
  lastName: «Щипунов»,
  fullName: function () {
    return this.firstName + » » + this.lastName;
  }
}
myObject.fullName(); // Будет возвращать «Андрей Щипунов»

Метод fullName — это функция. Функция принадлежит объекту myObject является владельцем функции.

То, что называется , является объектом, который «владеет» кодом JavaScript.
В данном случае значение является myObject.

Проверьте! Измените метод fullName, чтобы вернуть значение :

Пример

var myObject = {  firstName:»Андрей»,
  lastName: «Щипунов»,
  fullName: function () {
    return this;
  }}
myObject.fullName(); // Вернет (владельц object)

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

Неотложные функции

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

Есть два наиболее распространенных синтаксиса:

(function optional_function_name() {
  //body
}());
(function optional_function_name() {
  //body
})();

Могут всречаться и другие способы:

// Другие способы
!function() { /* ... */ }();
+function() { /* ... */ }();
new function() { /* ... */ };

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

var page_language = (function () {
  var lang;
  // Код для получения языка страницы
  return lang;
})();

9) onReady()

Для инициализации страницы исторически использовалось событие window.onload, которое срабатывает после полной загрузки страницы и всех объектов на ней: счетчиков, картинок и т.п.

Событие — гораздо лучший выбор в 99% случаев. Это событие срабатывает, как только готов DOM документ, до загрузки картинок и других не влияющих на структуру документа объектов.

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

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

function bindReady(handler){

	var called = false

	function ready() { // (1)
		if (called) return
		called = true
		handler()
	}

	if ( document.addEventListener ) { // (2)
		document.addEventListener( "DOMContentLoaded", function(){
			ready()
		}, false )
	} else if ( document.attachEvent ) {  // (3)

		// (3.1)
		if ( document.documentElement.doScroll && window == window.top ) {
			function tryScroll(){
				if (called) return
				if (!document.body) return
				try {
					document.documentElement.doScroll("left")
					ready()
				} catch(e) {
					setTimeout(tryScroll, 0)
				}
			}
			tryScroll()
		}

		// (3.2)
		document.attachEvent("onreadystatechange", function(){

			if ( document.readyState === "complete" ) {
				ready()
			}
		})
	}

	// (4)
    if (window.addEventListener)
        window.addEventListener('load', ready, false)
    else if (window.attachEvent)
        window.attachEvent('onload', ready)
    /*  else  // (4.1)
        window.onload=ready
	*/
}
readyList = []

function onReady(handler) {

	if (!readyList.length) {
		bindReady(function() {
			for(var i=0; i<readyList.length; i++) {
				readyList()
			}
		})
	}

	readyList.push(handler)
}

Использование:

onReady(function() {
  // ... 
})

Подробное описание функций , и принципы их работы вы можете почерпнуть в статье Кроссбраузерное событие onDOMContentLoaded.

Возвращаемые значения

Функции могут не только принимать входящие данные из внешней программы, но и способны пере­давать обратно значения по завершении своих инструкций. Для возврата значения используется инструкция return.

Инструкция return имеет следующий синтаксис:

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

Выполнить код »
Скрыть результаты

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

Инструкция может быть расположена в любом месте функции. После инструкции происходит выход из функции. Все операторы, расположенные в коде по­сле инструкции , не будут выполнены, например:

Выполнить код »
Скрыть результаты

В инструкции можно указать сразу выражение, перепишем нашу
функцию :

Выполнить код »
Скрыть результаты

Внутри функции можно использовать несколько инструкций :

Выполнить код »
Скрыть результаты

В случае, если в функции нет инструкции или указана без аргументов, то функция вернёт значение :

Выполнить код »
Скрыть результаты

Усиливаем пример с определением имени. Тесты

const myFunc  = function() { };                       //  1 const myFuncA = function myFuncA2() { };              //  2const myFuncB = () => { };                            //  3const myFuncC = new Function();                       //  4const property = Symbol('symbolProperty');const myObject = {   methodA: function() { },                            //  5  methodB: function MyMethodB() {},                   //  6  methodC: () => { },                                 //  7  methodD(){ },                                       //  8  (){ }                                     //  9};function myFuncD() { };                               // 10(function() { })();                                   // 11(function myFuncF(){ })();                            // 12

Теперь, используя описанные способы выше, возьмём у каждой функции свойство name, и начнем с функций, заданных как :

myFunc.name                       // "myFunc"myFuncA.name                      // "myFuncA"myFuncB.name                      // "myFuncB"myFuncC.name                      // "myFuncC"

Функции, объявленные как Object Method:

myObject.methodA.name             // "methodA"myObject.methodB.name             // "MyMethodB"myObject.methodC.name             // "methodC"myObject.methodD.name             // "methodD"myObject.name           // ""

Функции, объявленные как IIFE (Immediately-invoked function expression):

(function myFuncD() { }).name     // "myFuncD"(function() { }).name             // ""(function myFuncF(){ }).name      // "myFuncF"(new Function()).name             // "anonymous"

Вопросов возникает ещё больше. А может функция в опросе из twitter все таки именованная? Может я ввел вас в заблуждение?

Вложенные функции

Функция называется «вложенной», когда она создаётся внутри другой функции.

Это очень легко сделать в JavaScript.

Мы можем использовать это для упорядочивания нашего кода, например, как здесь:

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

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

Не важно где, она всё так же будет иметь доступ к тем же внешним переменным

Например, здесь, вложенная функция присваивается новому объекту в конструкторе:

А здесь мы просто создаём и возвращаем функцию «счётчик»:

Давайте продолжим с примером . Он создаёт функцию «counter», которая возвращает следующее число при каждом вызове. Несмотря на простоту, немного модифицированные варианты этого кода применяются на практике, например, в генераторе псевдослучайных чисел и во многих других случаях.

Как же это работает изнутри?

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

  1. Локальные переменные вложенной функции…
  2. Переменные внешней функции…
  3. И так далее, пока не будут достигнуты глобальные переменные.

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

Теперь рассмотрим два вопроса:

  1. Можем ли мы каким-нибудь образом сбросить счётчик из кода, который не принадлежит ? Например, после вызова в коде выше.
  2. Если мы вызываем несколько раз – нам возвращается много функций . Они независимы или разделяют одну и ту же переменную ?

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

Готовы?

Хорошо, давайте ответим на вопросы.

  1. Такой возможности нет: – локальная переменная функции, мы не можем получить к ней доступ извне.
  2. Для каждого вызова создаётся новое лексическое окружение функции, со своим собственным . Так что, получившиеся функции – независимы.

Вот демо:

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

Переходим к нескольким аргументам с «func.apply»

Теперь давайте сделаем ещё более универсальным. До сих пор он работал только с функциями с одним аргументом.

Как же кешировать метод с несколькими аргументами ?

Здесь у нас есть две задачи для решения.

Во-первых, как использовать оба аргумента и для ключа в коллекции ? Ранее для одного аргумента мы могли просто сохранить результат и вызвать , чтобы получить его позже. Но теперь нам нужно запомнить результат для комбинации аргументов . Встроенный принимает только одно значение как ключ.

Есть много возможных решений:

  1. Реализовать новую (или использовать стороннюю) структуру данных для коллекции, которая более универсальна, чем встроенный , и поддерживает множественные ключи.
  2. Использовать вложенные коллекции: будет , которая хранит пару . Тогда получить мы сможем, вызвав .
  3. Соединить два значения в одно. В нашем конкретном случае мы можем просто использовать строку как ключ к . Для гибкости, мы можем позволить передавать хеширующую функцию в декоратор, которая знает, как сделать одно значение из многих.

Для многих практических применений третий вариант достаточно хорош, поэтому мы будем придерживаться его.

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

Вот более мощный :

Теперь он работает с любым количеством аргументов.

Есть два изменения:

  • В строке вызываем для создания одного ключа из . Здесь мы используем простую функцию «объединения», которая превращает аргументы в ключ . В более сложных случаях могут потребоваться другие функции хеширования.
  • Затем в строке используем для передачи как контекста, так и всех аргументов, полученных обёрткой (независимо от их количества), в исходную функцию.

Вместо мы могли бы написать .

Синтаксис встроенного метода func.apply:

Он выполняет , устанавливая и принимая в качестве списка аргументов псевдомассив .

Единственная разница в синтаксисе между и состоит в том, что ожидает список аргументов, в то время как принимает псевдомассив.

Эти два вызова почти эквивалентны:

Есть только одна небольшая разница:

  • Оператор расширения позволяет передавать перебираемый объект в виде списка в .
  • А принимает только псевдомассив .

Так что эти вызовы дополняют друг друга. Для перебираемых объектов сработает , а где мы ожидаем псевдомассив – .

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

Передача всех аргументов вместе с контекстом другой функции называется «перенаправлением вызова» (call forwarding).

Простейший вид такого перенаправления:

При вызове из внешнего кода его не отличить от вызова исходной функции.

«this» не является фиксированным

В JavaScript ключевое слово «this» ведёт себя иначе, чем в большинстве других языков программирования. Оно может использоваться в любой функции.

В этом коде нет синтаксической ошибки:

Значение вычисляется во время выполнения кода и зависит от контекста.

Например, здесь одна и та же функция назначена двум разным объектам и имеет различное значение «this» при вызовах:

Правило простое: при вызове значение внутри равно . Так что, в приведённом примере это или .

Вызов без объекта:

Мы даже можем вызвать функцию вовсе без использования объекта:

В строгом режиме () в таком коде значением будет являться . Если мы попытаемся получить доступ к , используя – это вызовет ошибку.

В нестрогом режиме значением в таком случае будет глобальный объект ( для браузера, мы вернёмся к этому позже в главе Глобальный объект). Это – исторически сложившееся поведение , которое исправляется использованием строгого режима ().

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

Последствия свободного

Если вы до этого изучали другие языки программирования, тогда вы, скорее всего, привыкли к идее «фиксированного » – когда методы, определённые внутри объекта, всегда сохраняют в качестве значения ссылку на свой объект (в котором был определён метод).

В JavaScript является «свободным», его значение вычисляется в момент вызова метода и не зависит от того, где этот метод был объявлен, а зависит от того, какой объект вызывает метод (какой объект стоит «перед точкой»).

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

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

Вызов функции с помощью конструктора функций

Если вызову функции предшествует ключевое слово , то это вызов конструктора.

Похоже, что вы создаете новую функцию, но поскольку функции JavaScript являются объектами, вы фактически создаете новый объект:

Пример

// Это конструктор функций:function myFunction(arg1, arg2) {
  this.firstName = arg1;
  this.lastName  = arg2;
}
// This создает новый объект
var x = new myFunction(«Андрей», «Щипунов»);
x.firstName; // Будет возвращать «Андрей»

Вызов конструктора создает новый объект. Новый объект наследует свойства и методы от своего конструктора.

Ключевое слово в конструкторе не имеет значения.
Значением параметра будет новый объект, созданный при вызове функции.

Итого

Основные улучшения в функциях:

  • Можно задавать параметры по умолчанию, а также использовать деструктуризацию для чтения приходящего объекта.
  • Оператор spread (троеточие) в объявлении позволяет функции получать оставшиеся аргументы в массив: .
  • Тот же оператор spread в вызове функции позволяет передать в неё массив как список аргументов (вместо ).
  • У функции есть свойство , оно содержит имя, указанное при объявлении функции, либо, если его нет, то имя свойства или переменную, в которую она записана. Есть и некоторые другие ситуации, в которых интерпретатор подставляет «самое подходящее» имя.
  • Объявление Function Declaration в блоке видно только в этом блоке.
  • Появились функции-стрелки:
    • Без фигурных скобок возвращают выражение : .
    • С фигурными скобками требуют явного .
    • Не имеют своих и , при обращении получают их из окружающего контекста.
    • Не могут быть использованы как конструкторы, с .
Добавить комментарий

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

Adblock
detector