Что такое функция литерал
Перейти к содержимому

Что такое функция литерал

  • автор:

3.4.1. Функциональные литералы

В предыдущем разделе мы видели определение функции square(). С помощью этого синтаксиса обычно описывается большинство функций в JavaScriptпрограммах. Однако стандарт ECMAScript v3 предоставляет синтаксис (реализованный в JavaScript 1.2 и более поздних версиях) для определения функциональных литералов. Функциональный литерал задается с помощью ключевого слова function, за которым следуют необязательное имя функции, список аргументов функции, заключенный в круглые скобки, и тело функции в фигурных скобках. Другими словами, функциональный литерал выглядит так же, как определение функции, правда, у него может не быть имени. Самое большое различие состоит в том, что функциональные литералы могут входить в другие JavaScriptвыражения. То есть функцию square() не обязательно задавать в виде определения: function square(x) < return x*x; >Ее можно задать с помощью функционального литерала: var square = function(x) < return x*x; >Функции, определенные таким образом, иногда называют лямбдафункциями. Это дань уважения языку программирования LISP, который одним из первых допускал вставку неименованных функций в виде литералов внутрь программы. Хотя в данный момент польза от функциональных литералов может быть неочевидной, позднее, в сложных сценариях мы увидим, что они бывают довольно удобными и полезными. Имеется еще один способ определения функции: можно передать список аргументов и тело функции в виде строк в конструктор Function(). Например: var square = new Function(«x», «return x*x;»); Такое определение функций используется редко. Обычно неудобно задавать тело функции в виде строки, и во многих реализациях JavaScript функции, определенные подобным образом, менее эффективны, чем функции, определенные любым из двух других способов. 6.14. Инструкция function Инструкция function в JavaScript определяет функцию. Она имеет следующий синтаксис: function имя_функции([арг1 [,арг2 [. аргn]]]) < инструкции >Здесь имя_функции – это имя определяемой функции. Оно должно быть идентификатором, а не строкой или выражением. За именем функции следует заключенный в скобки список имен аргументов, разделенных запятыми. Эти идентификаторы могут использоваться в теле функции для ссылки на значения аргументов, переданных при вызове функции. Тело функции состоит из произвольного числа JavaScriptинструкций, заключенных в фигурные скобки. Эти инструкции не исполняются при определении функции. Они компилируются и связываются с новым объектом функции для исполнения при ее вызове с помощью оператора вызова (). Обратите внимание, что фигурные скобки – это обязательная часть инструкции function. В отличие от блоков инструкций в циклах while и других конструкциях, тело функции требует фигурных скобок, даже если оно состоит только из одной инструкции. Определение функции создает новый объект функции и сохраняет объект в только что созданном свойстве с именем имя_функции. Вот несколько примеров определений функций: function welcome() < alert("Добро пожаловать на мою домашнюю страницу!"); >function print(msg) < document.write(msg, "
«); > function hypotenuse(x, y) < return Math.sqrt(x*x + y*y); // Инструкция return описана далее >function factorial(n) < // Рекурсивная функция if (n Определения функций обычно находятся в JavaScriptкоде верхнего уровня. Они также могут быть вложенными в определения других функций, но только на «верхнем уровне», т. е. определения функции не могут находиться внутри инструкций if, циклов while или любых других конструкций. Формально function не является инструкцией. Инструкции приводят к некоторым динамическим действиям в JavaScriptпрограмме, а определения функций описывают статическую структуру программы. Инструкции исполняются вовремя исполнения программы, а функции определяются во время анализа или компиляции JavaScriptкода, т. е. до их фактического исполнения. Когда синтаксический анализатор JavaScript встречает определение функции, он анализирует и сохраняет (без исполнения) составляющие тело функции инструкции. Затем он определяет свойство (в объекте вызова, если определение функции вложено в другую функцию; в противном случае – в глобальном объекте) с именем, которое было указано в определении функции. Тот факт, что функции определяются на этапе синтаксического анализа, а не во время исполнения, приводит к некоторым интересным эффектам. Рассмотрим следующий фрагмент: alert(f(4)); // Показывает 16. Функция f() может быть вызвана до того, // как она определена. var f = 0; // Эта инструкция переписывает содержимое свойства f. function f(x) < // Эта "инструкция" определяет функцию f до того, return x*x; // как будут выполнены приведенные ранее строки. >alert(f); // Показывает 0. Функция f() перекрыта переменной f. Такие необычные результаты возникают изза того, что функция определяется не в то время, в которое определяется переменная. К счастью, подобные ситуации возникают не очень часто. В главе 8 мы узнаем о функциях больше. 6.15. Инструкция return Как вы помните, вызов функции с помощью оператора () представляет собой выражение. Все выражения имеют значения, и инструкция return служит для определения значения, возвращаемого функцией. Это значение становится значением выражения вызова функции. Инструкция return имеет следующий синтаксис: return выражение; Инструкция return может располагаться только в теле функции. Присутствие ее в любом другом месте является синтаксической ошибкой. Когда выполняется инструкция return, вычисляется выражение и его значение возвращается в качестве значения функции. Инструкция return прекращает исполнение функции,даже если в теле функции остались другие инструкции. Инструкция return используется для возвращения значения следующим образом: function square(x) < return x*x; >Инструкция return может также использоваться без выражения, тогда она просто прерывает исполнение функции, не возвращая значение. Например: function display_object(obj) < // Сначала убедимся в корректности нашего аргумента // В случае некорректности пропускаем остаток функции if (obj == null) return;6.16. Инструкция throw 115 // Здесь находится оставшаяся часть функции. >Если в функции выполняется инструкция return без выражения или если выполнение функции прекращается по причине достижения конца тела функции, значение выражения вызова функции оказывается неопределенным (undefined). JavaScript вставляет точку с запятой автоматически, поэтому нельзя разделять переводом строки инструкцию return и следующее за ней выражение. 8.3. Функции как данные Самые важные особенности функций заключаются в том, что они могут определяться и вызываться, что было показано в предыдущем разделе. Определение и вызов функций – это синтаксические средства JavaScript и большинства других языков программирования. Однако в JavaScript функции – это не только синтаксические конструкции, но и данные, а это означает, что они могут присваиваться переменным, храниться в свойствах объектов или элементах массивов, передаваться как аргументы функциями и т. д.1 Чтобы понять, как в JavaScript функции могут быть одновременно синтаксическими конструкциями и данными, рассмотрим следующее определение функции: function square(x) < return x*x; >Это определение создает новый объект функции и присваивает его переменной square. Имя функции действительно нематериально – это просто имя переменной, содержащей функцию. Функция может быть присвоена другой переменной, и при этом работать так же, как и раньше: var a = square(4); // a содержит число 16 var b = square; // b теперь ссылается на ту же функцию, что и square var c = b(5); // c содержит число 25 Функции могут быть также присвоены не только глобальным переменным, но и свойствам объектов. В этом случае их называют методами: var o = new Object; o.square = function(x) < return x*x; >; // функциональный литерал y = o.square(16); // y равно 256 У функций даже не обязательно должны быть имена, например в случае присваивании их элементам массива: var a = new Array(3); a[0] = function(x) < return x*x; >a[1] = 20; a[2] = a[0](a[1]); // a[2] содержит 400 Синтаксис вызова функции в последнем примере выглядит необычно, однако это вполне допустимый вариант применения оператора () в JavaScript! В примере 8.2 подробно показано, что можно делать, когда функции выступают в качестве данных. Этот пример демонстрирует, каким образом функции могут передаваться другим функциям. Хотя пример может показаться вам несколько сложным, комментарии объясняют, что происходит, и он вполне достоин тщательного изучения. Пример 8.2. Использование функций как данных // Здесь определяются несколько простых функций function add(x,y) < return x + y; >function subtract(x,y) < return x y; >function multiply(x,y) < return x * y; >function divide(x,y) < return x / y; >// Эта функция принимает одну из вышеприведенных функций // в качестве аргумента и вызывает ее для двух операндов function operate(operator, operand1, operand2) < return operator(operand1, operand2); >// Вот так можно вызвать эту функцию для вычисления значения выражения (2+3) + (4*5): var i = operate(add, operate(add, 2, 3), operate(multiply, 4, 5)); // Ради примера, мы реализуем эти функции снова, на этот раз с помощью // функциональных литералов внутри литерала объекта. var operators = < add: function(x,y) < return x+y; >, subtract: function(x,y) < return xy; >, multiply: function(x,y) < return x*y; >, divide: function(x,y) < return x/y; >, pow: Math.pow // Для предопределенных функций это тоже работает >; // Эта функция принимает имя оператора, отыскивает оператор в объекте, // а затем вызывает его для переданных операндов. Обратите внимание // на синтаксис вызова функции оператора. function operate2(op_name, operand1, operand2) < if (typeof operators[op_name] == "function") return operators[op_name](operand1, operand2); else throw "неизвестный оператор"; >// Вот так мы можем вызвать эту функцию для вычисления значения // («hello» + » » + «world»): var j = operate2(«add», «hello», operate2(«add», » «, «world»)) // Используем предопределенную функцию Math.pow(): var k = operate2(«pow», 10, 2) Если предыдущий пример не убедил вас в удобстве передачи функций в качестве аргументов другим функциям и других способов использования функций как значений, обратите внимание на функцию Array.sort(). Она сортирует элементы массива. Существует много возможных порядков сортировки (числовой, алфавитный, по датам, по возрастанию, по убыванию и т. д.), поэтому функция sort() принимает в качестве необязательного аргумента другую функцию, которая сообщает о том, как выполнять сортировку. Эта функция делает простую работу получает два элемента массива, сравнивает их, а затем возвращает результат, указывающий, какой из элементов должен быть первым. Этот аргумент функции делает метод Array.sort() совершенно универсальным и бесконечно гибким –он может сортировать любой тип данных в любом мыслимом порядке! (Пример использования функции Array.sort() вы найдете в разделе 7.7.3.) 3.5. Объекты Объект – это коллекция именованных значений, которые обычно называют свойствами (properties) объекта. (Иногда они называются полями объекта, но употребление этого термина может сбить с толку.) Чтобы сослаться на свойство объекта, надо указать имя объекта, затем точку и имя свойства. Например, если объект под названием image имеет свойства width и height, мы можем сослаться на эти свойства следующим образом: image.width image.height Свойства объектов во многом похожи на JavaScriptпеременные – они могут содержать любой тип данных, включая массивы, функции и другие объекты. Поэтому можно встретить вот такой JavaScriptкод: document.myform.button Этот фрагмент ссылается на свойство button объекта, который, в свой очередь,хранится в свойстве myform объекта с именем document. Как упоминалось раньше, функция, хранящаяся в свойстве объекта, часто называется методом, а имя свойства становится именем метода. При вызове метода объекта сначала используется оператор «точка» для указания функции, а затем () для вызова этой функции. Например, метод write() объекта с именем document можно вызвать так: document.write(«это проверка»); Объекты в JavaScript могут выступать в качестве ассоциативных массивов, т. е. могут ассоциировать произвольные значения с произвольными строками. При такой работе с объектом обычно требуется другой синтаксис для доступа к его свойствам: строка, содержащая имя требуемого свойства, заключается в квадратные скобки. Тогда к свойствам объекта image, упомянутого ранее, можно обратиться посредством следующего кода: image[«width»] image[«height»] Ассоциативные массивы – это мощный тип данных; они полезны при реализации ряда технологий программирования. Об объектах, их традиционном применении и применении в качестве ассоциативных массивов рассказано в главе 7. 3.5.1. Создание объектов Как мы увидим в главе 7, объекты создаются путем вызова специальных функцийконструкторов. Все следующие строки создают новые объекты: var o = new Object(); var now = new Date(); var pattern = new RegExp(«\\sjava\\s», «i»); Создав собственный объект, можно его как угодно использовать и устанавливать его свойства: var point = new Object(); point.x = 2.3; point.y = 1.2;3.6. Массивы 53 3.5.2. Объектные литералы В JavaScript определяется синтаксис объектных литералов, позволяющий создавать объекты и указывать их свойства. Объектный литерал (также называемый инициализатором объекта) представляет собой список разделенных запятыми пар «свойство/значение», заключенный в фигурные скобки. Внутри пар роль разделителя играет двоеточие. Таким образом, объект point из предыдущего примера также может быть создан и инициализирован следующей строкой: var point = < x:2.3, y:1.2 >; Объектные литералы могут быть вложенными. Например: var rectangle = < upperLeft: < x: 2, y: 2 >, lowerRight: < x: 4, y: 4 >>; Наконец, значениями свойств в объектных литералах не обязательно должны быть константы – это могут быть произвольные JavaScriptвыражения. Кроме того, в качестве имен свойств в объектных литералах допускается использовать строковые значения: var square = < "upperLeft": < x:point.x, y:point.y >, ‘lowerRight’: < x:(point.x + side), y:(point.y+side) >>; 3.5.3. Преобразование объектов Когда непустой объект используется в логическом контексте, результатом преобразования является значение true. Когда объект используется в строковом контексте, преобразование выполняется методом toString() объекта и в дальнейших вычислениях участвует строка, возвращаемая этим методом. Когда объект используется в числовом контексте, сначала вызывается метод объекта valueOf(). Если этот метод возвращает числовое значение примитивного типа, в дальнейших вычислениях участвует это значение. Однако в большинстве случаев метод valueOf() возвращает сам объект. В такой ситуации объект сначала преобразуется в строку вызовом метода toString(), а затем выполняется попытка преобразовать строку в число.Проблема преобразования объектов в значения примитивных типов имеет свои тонкости, и мы еще вернемся к ней в конце главы.

17.05.2015 1.4 Mб 23 ApplLin.pdf

17.05.2015 410.11 Кб 20 APP_otvety.doc

18.03.2016 532.99 Кб 15 Arbitrazhny_protsess.doc

24.09.2019 2.11 Mб 3 artem.doc

17.05.2015 12.17 Mб 116 ar_1177_a_1185_ly_bash_1185_orttar.pdf

08.08.2019 190.09 Кб 1 ASCII и latin.docx

23.11.2018 546.82 Кб 27 astrology.doc

26.09.2019 79.59 Кб 23 Audit.docx

21.12.2018 454.14 Кб 25 Audit_vse_voprosy.doc

08.09.2019 67.58 Кб 20 AUSTRALIA.Location.doc

08.09.2019 48.64 Кб 22 AUSTR_III_culture_2003.doc

Ограничение

Для продолжения скачивания необходимо пройти капчу:

Ruby: Что такое литерал?

Литералы есть в любых языках программирования, не только в ruby.

Литерал (англ. literal — «буквальный») — это буквальное (прямо написанное/указанное) значение. В общем смысле — это любое фиксированное значение прописанное в код явно.

Когда вы переменной присваиваете конкретное значение (например, число 0 ), то запись в коде 0 — это числовой литерал.

Кроме числовых, могут быть строковые литералы — когда вы переменной присваиваете строку. Вот пример строкового литерала (несколько букв в одинарных кавычках).

'Саша' 

И более сложные варианты — например, при объявлении пустого хэша/массива с помощью двух квадратных/фигурных скобок мы также используем литералы [] / <> .

Аналогично, массив, полностью состоящий из литералов — тоже является литералом.

['Саша', 'Вова', 'Женя'] 

Важно: в ruby массивы, состоящие из двух или более строк без пробелов принято записывать другим литералом:

%w[Саша Вова Женя] 

В ruby есть ещё символы, конечно, запись символа в коде тоже делается литералом:

:fine 

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

Литерал (информатика)

Литерал (англ. literal — константа) — запись в исходном коде компьютерной программы, представляющая собой фиксированное значение [1] .

Описание

Литералы представляют собой константы, непосредственно включаемые в текст программы в отличие от прочих данных — констант и переменных, обращение к которым осуществляется посредством ссылок [1] . Литералы не могут быть изменены в тексте программы.

В следующем примере 1 и Кот это литералы, а a1, c и cat — переменные:

int a1=1; int c=a1; string cat="Кот";

Литерал в языке Python — это выражение, создающее объект.

Типы литералов

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

Обычно выделяют следующие элементарные типы литералов:

Числовые литералы — литералы, для записи чисел. Иногда, числовые литералы детализируются целые литералы, дробные литералы, с различной точностью представления и записанные в различной системе счисления (например, битовые литералы в PL/I). Обычно, в программах числовые литералы записываются непосредственно числом. В следующем примере 100 и 3.1415 — числовые литералы:

int a=100; float b=3.1415;

Строковые литералы, обычно, представляют собой строку символов, заключённую в кавычки или скобки. Иногда выделяют, также, символьные литералы, включающие один символ. В разных языках программирования допускаются различные типы кавычек. Например, в следующем примере на языке JavaScript один и два — строковые литералы записанные с использованием различных допустимых типов кавычек:

var one="один"; var two='два';

Логические литералы, Логические значения — два литерала: true и false или их аналоги — T, t, Y, y, F, f, N, n, NIL и т. п.. Например:

bool t=true; bool f=false;

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

Null-литерал, Пустое значение — особый тип литерала, в зависимости от языка программирования, относящийся к ссылочному либо объектному типу. Единственное допустимое значение этого типа литералов null, или аналог, например NIL, None, Nothing — ссылка никуда не ведёт либо объект отсутствует.

T o=null;

Регулярные выражения. В некоторых языках программирования регулярные выражения представляют собой литерал особого типа для поиска по шаблону [2] . Например:

/javascript/gi

В некоторых объектно ориентированных языках программирования (например, ECMAScript v3) допускается использовать выражения, которые служат массивами-литералами и объектами-литералами [2] . Например:

[1,2,3,4,5] // Инициализатор массива // Инициализатор объекта

Иногда анонимные функции относят к литералам-функциям, а анонимные объекты к литералам-объектам.

Примечания

  1. 12 Статья literal в Энциклопедии PC Magazine
  2. 12 Флэнаган Д. JavaScript. Подробное руководство. — Пер. с англ. — СПб: Символ-Плюс, 2008. — 992 с., ил.

Ссылки

  • Literals (англ.)

Лекция 9. Литералы объектов, JSON, функции обратного вызова

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

Объекты JS могут содержать данные и обладать методами. Но в отличие от других ЯП эти элементы в объекте заранее не объявлены, мы создаём их динамически, по мере необходимости.

var ride = new Object(); ride.make = ‘Yamaha’; ride.model = ‘V-Star Silverado’ ride.year = 2005; ride.purchased = new Date(2005,3,15);

Мы создаём новый экземпляр Object и присваиваем его переменной ride. Затем заполняем эту переменную рядом свойств различных типов: два строковых свойства, числовое свойство и свойство типа Date.

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

Предположим, нам требуется изменить значение даты покупки:

ride.purchased = new Date(2005,2,1);

Ничего страшного… если мы случайно не сделаем опечатку, например:

ride.purcahsed = new Date(2005,2,1);

Как вы знаете, в JS нет компилятора, который бы предупредил бы вас о сделанной ошибке; новое свойство с именем purcahsed, позже вызовет ряд проблем в работе вашей программы. Частично в решении таких проблем вам может помочь Firebug.

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

Т.о. основная цель экземпляра Object – служить контейнером для именованных наборов других объектов.

Предположим, мы добавили к нашему объекту ride новое свойство, описывающее владельца транспортного средства. Это свойство – еще один объект JS, который в свою очередь содержит такие свойства, как имя и профессия владельца:

var owner = new Object(); owner.name = ‘Konstantin Volodin’; owner.occupation = ‘bounty hunter’; ride.owner = owner;

Обращение к вложенным свойствам можно описать так:

var ownerName = ride.owner.name;

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

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

До этого момента мы ссылались на свойства объекта с помощью опрератора «точка», но он является синонимом более общего оператора для выполнения ссылок на свойства.

Что делать, если есть свойство с именем color.scheme? Точка в середине имени портит всё дело. Интерпретатор JS будет пытаться найти scheme как вложенное свойство color. Такая же проблема будет с другими символами, пробельными и специальными. Для таких случаев используется более общий формат обращения к свойствам:

object[propertyNameExpression]

propertyNameExpression – выражение JS, которое определяется как строка, формирующая имя свойства, к которому происходит обращение. Например, все три следующие ссылки эквивалентны:

ride.make ride[‘make’] ride[‘m’+’a’+’k’+’e’]
var p = ‘make’; ride[p];

Применение общего оператора ссылки – единственный способ обратиться к свойствам, имена которых не являются допустимыми идентификаторами JS, например:

ride[“a property name that’s rather odd”]

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

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

Литералы объектов.

Литералами называют представление значения некоторого типа данных. В следующем примере 2 и Пример это литералы, а a2, d и example — переменные:

int a2 = 2; int d = a2; string example = "Пример";

При создании объекта ride , моделирующего некоторые свойства мотоцикла, мы использовали два оператора new, промежуточную переменную с именем owner и много операторов присваивания. Это утомительно.

Можно использовать более компактную и удобную для визуального восприятия запись

var ride = < make: ‘Yamaha’, model: ‘V-Star Silverado’, year: 2005, purchased: new Date(2005,3,15), owner: < name: ‘Konstantin Volodin’, occupation: ‘bounty hunter’, >>;

В это фрагменте с помощью литерала объекта создаётся тот же самый объект ride, который в предыдущем разделе мы создали с помощью операторов присваивания.

Большинство авторов страниц отдают предпочтение такой форме записи, называемой JSON (JavaScript Object Notation). Структура этой формы записи очень проста – объект обозначается парой фигурных скобок, внутри которых через запятую перечислены свойства. Каждое свойство обозначается путём записи его имени и значения, разделённых символом двоеточия.

Как видно из объявления свойства owner, объявления объектов могут быть вложенными.

Кстати, точно также в формате JSON можно описывать массивы, поместив список элементов, разделённых запятыми, в квадратные скобки:

var someValues = [2,4,5,8,9,12,14,16,17,23,36];

JSON (JavaScript Object Notation) — простой формат обмена данными, удобный для чтения и написания как человеком, так и компьютером. JSON — текстовый формат, полностью независимый от языка реализации, но он использует соглашения, знакомые программистам C-подобных языков, таких как C, C++, C#, Java, JavaScript, Perl, Python и многих других. Эти свойства делают JSON идеальным языком обмена данными.

  • Коллекция пар ключ/значение. В разных языках, эта концепция реализована как объект, запись, структура, словарь, хэш, именованный список или ассоциативный массив.
  • Упорядоченный список значений. В большинстве языков это реализовано как массив, вектор, список или последовательность.

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

В нотации JSON это выглядит так:

Объект — неупорядоченный набор пар ключ/значение. Объект начинается с < (открывающей фигурной скобки) и заканчивается >(закрывающей фигурной скобкой). Каждое имя сопровождается : (двоеточием), пары ключ/значение разделяются , (запятой).

Массив — упорядоченная коллекция значений. Массив начинается с [ (открывающей квадратной скобки) и заканчивается ] (закрывающей квадратной скобкой). Значения разделены , (запятой).

Значение может быть строкой в двойных кавычках, числом, true , false , null , объектом или массивом. Эти структуры могут быть вложенными.

Строка — коллекция нуля или больше символов Unicode, заключенная в двойные кавычки, используя \ (обратную косую черту) в качестве символа экранирования. Символ представляется как односимвольная строка. Похожий синтаксис используется в C и Java.

Число представляется так же, как в C или Java, кроме того, что используется только десятичная система счисления.

Пробелы могут использоваться между любыми лексемами.

Вернёмся к нашему объекту ride.

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

Объекты как свойства объекта window

До этого момента мы видели два способа хранения ссылок на объекты JS – в переменных и в свойствах.

var aVariable = ‘No one can draw a clear line between sane and insane.’; someObject.aProperty = ‘You move that line as you see fit for yourself.’;

В этих двух инструкциях два экземпляра String (созданные с помощью литералов) присваиваются переменной и свойству объекта соответственно, с помощью операторов присваивания.

Однако, действительно ли эти инструкции выполняют разные операции? Как выясняется – нет!

Когда ключевое слово var используется на глобальном уровне, за пределами какой-либо функции, эта удобная для программиста форма записи является всего лишь ссылкой на свойство предопределённого объекта JS window. Любая глобальная ссылка неявно превращается в свойство объекта window.

Это означает, что эквивалентны все следующие инструкции:

var foo = bar; window.foo = bar; foo = bar;

Независимо от формы записи во всех трёх случаях создается свойство объекта window с именем foo (если оно не существовало), и ему присваивается значение bar. Кроме того, поскольку идентификатор bar никак не квалифицирован, предполагается, что он представляет собой имя свойства объекта window.

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

В целом, обзор объекта Object в языке JavaScript завершен. Были рассмотрены следующие важные понятия:

  • Объект в JS – это неупорядоченный набор свойств.
  • Свойство состоит из имени и значения.
  • Можно объявлять объекты посредством литералов объектов.
  • Глобальные переменные являются свойствами объекта window.

Функции как обычные объекты

В языке JS функции считаются объектами, подобно объектам любого другого типа, например string, number или Date. Как и другие объекты, функции определяются конструктором JS, в данном случае – Function, и могут:

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

Поскольку в некоторых случаях функции рассматриваются как объекты, мы говорим, что функции – это обычные объекты. И несмотря на то, что они обладают не только значением (тело функции), но ещё и именем, функции не отличаются от других объектов JS.

Что есть имя?

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

Рассмотрим объект типа Number. Инструкция

Вполне правильна, но совершенно бесполезна. Экземпляр Number не всегда полезен, если не присваивается свойству или переменной или не связан с именем параметра. Мы просто не сможем обратиться к такому экземпляру. Это же относится и к экземплярам объектов Function.

function doSmthWonderful()

Не создаёт функцию с именем doSmthWonderful. Ключевое слово function автоматически создаёт экземпляр Function и присваивает его свойству window, имя которого совпадает с «именем» функции, как показано в следующем примере:

doSmthWonderful = function()

Это аналогично объявлению переменной с литералом Number

aWonderfulNumber = 213;

Здесь нет ничего странного, и инструкция присваивания функции глобальной переменной (свойству объекта window) ничем не отличается – литерал функции используется для создания экземпляра Function, а затем присваивается переменной doSmthWonderful так же, как литерал 213 объекта Number был использован для присваивания экземпляра Number переменной aWonderfulNumber.

Литерал функции состоит из ключевого слова function, за которым идёт список параметров, заключённый в круглые скобки, и далее следует тело функции.

Когда мы объявляем глобальную именованную функцию, создаётся экземпляр Function и присваивается свойству объекта window, которое создаётся автоматически, на основе так называемого имени функции. Сам по себе экземпляр Function не имеет имени, как литерал Number или String. Это понятие иллюстрирует рисунок:

Рисунок 5. Экземпляр Function является неименованным объектом, таким же, как значение 213 типа Number или любое другое значение JavaScript.
Он именуется только ссылками, которые созданы для него.

Помните, что, когда в HTML-странице создаётся глобальная переменная, она создаётся как свойство объекта window. Поэтому все следующие инструкции эквивалентны:

function hello() hello = function() < alert(‘Hi there!’); >window.hello = function()

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

Мы рассмотрели примеры присваивания функций переменным и свойствам – а как насчет передачи функции в качестве параметра?

Функции обратного вызова

Глобальные функции хороши, когда программный код следует красивым и упорядоченным синхронным потоком, но характерной чертой HTML-страниц сразу после загрузки является асинхронность. Будь то обработка событий, установка таймеров или выполнение запросов Ajax, программный код веб-страницы по своей природе является асинхронным. И одно из самых распространённых понятий в асинхронном программировании – понятие функции обратного вызова.

Возьмём в качестве примера таймер. Мы можем заставить таймер сработать, например, через 5 секунд, передав соответствующее значение длительности методу window.setTimeout(). Но каким образом этот метод сообщить нам о том, что время таймера истекло, чтобы мы могли выполнить необходимые действия по истечении времени ожидания? Делается это путём вызова функции, котору мы предоставим.

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

function hello() setTimeout(hello,5000);

Мы объявляем функцию с именем hello и устанавливаем таймер на 5 секунд, заданных во втором параметре как 5000 миллисекунд. В первом параметре мы передаём методу SetTimeout() ссылку на функцию. Передача функции в виде параметра ничем не отличается от передачи любого другого значения – точно также мы передали во втором параметре значение Number.

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

Однако, создание имени hello не является необходимостью. Если функцию не требуется вызывать где-нибудь в другом месте страницы, нет никакой необходимости создавать свойство hello в объекте window, чтобы на мгновение сохранить экземпляр Function и потом передать его в качестве параметра.

Вот более изящный способ записи этого фрагмента:

setTimeout(function() < alert(‘Hi there!’); >,5000);

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

Мы также можем присваивать экземпляры Function свойствам объектов, и эта возможность действительно представляет интерес.

В объектно-ориентированных языках, основанных на классах, указатель this, как правило, ссылается на экземпляр класса, в пределах которого был объявлен метод. В JS, где функции являются обычными объектами, они не объявляются как часть чего либо. Объект, на который ссылается this, называется контекстом функции и определяется не тем, как функция объявляется, а тем, как она вызывается.

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

var ride = < make: ‘Yamaha’, model: ‘V-Star Silverado’, year: 2005, purchased: new Date(2005,3,15), owner: < name: ‘Konstantin Volodin’, occupation: ‘bounty hunter’, >whatAmI: function() < return this.year + ‘ ‘ + this.make + ‘ ‘ + this.model; >>;

К первоначальному коду добавилось свойство с именем WhatAmI которое ссылается на экземпляр Function. Новая иерархия объектов показана на рисунке:

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

Если функция вызывается через свойство

var bike = ride.whatAmI();

то в качестве контекста функции (ссылка this) устанавливается экземпляр объекта, на который указывает ride. В результате в переменную bike записывается строка 2005 Yamaha V-Star Silverado, потому что функция выбирает с помощью this значения свойств объекта, посредством которого она была вызвана.

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

JS позволяет нам чётко установить, что будет использовано в качестве контекста функции. Мы можем передать в контексте функции всё, что угодно, вызвав функцию с помощью метода call() или apply() экземпляра Function.

Кроме того, будучи обычными объектами, даже функции имеют методы, определяемые конструктором Function.

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

Пришло время для более обстоятельного примера.

  Function Context Example   

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

Затем мы определяем глобальную функцию, которая возвращает значение свойства handle для любого объекта, используемого в качестве контекста функции v, и присваиваем ту же самую функцию свойству identifyMe w объекта o1. Можно сказать, что тем самым был создан метод объекта o1 с именем identifyMe, хотя важно отметить, что функция объявляется независимо от объекта.

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

Эта последовательность сообщений иллюстрирует следующее:

  • Если функция вызывается как глобальная функция, контекстом функции является экземпляр объекта window x.
  • Если функция вызывается как свойство объекта (o1 в данном случае), контекстом функции становится этот объект y. Мы могли бы сказать, что функция действует как метод этого объекта – аналогично ОО языкам. Но это не совсем так.
  • Использование метода call() объекта Function приводит к тому, что контекстом функции становится любой объект, полученный методом call() в качестве первого параметра, — в данном случае о2 z. В этом примере функция действует как метод объекта o2 при том, что она никак не связана с объектом о2, даже как свойство.
  • Как и в случае с методом call(), при использовании метода apply() контекстом функции становится любой объект, переданный в качесвте первого параметра

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

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

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

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

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

Замыкание (closure) – это экземпляр Function вместе с локальными переменными из его окружения, необходимыми для выполнения.

Добавить комментарий

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