Вам бонус- начислено 1 монета за дневную активность. Сейчас у вас 1 монета

Псевдо-массив arguments

Лекция



Привет, сегодня поговорим про псевдо-массив arguments, обещаю рассказать все что знаю. Для того чтобы лучше понимать что такое псевдо-массив arguments , настоятельно рекомендую прочитать все из категории Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend).


  1. Доступ к «лишним» аргументам
    1. Пример использования: copy(dst, src1,...)
  2. arguments.callee и arguments.callee.caller
    1. arguments.callee
    2. arguments.callee.caller
    3. Почему callee и caller устарели?

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

Например:

 

   
1 function go(a,b) {
2   alert("a="+a+", b="+b);
3 }
4  
5 go(1);     // a=1, b=undefined
6 go(1,2);   // a=1, b=2
7 go(1,2,3); // a=1, b=2, третий аргумент не вызовет ошибку

 

 

В JavaScript нет «перегрузки» функций

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

01 function log(a) {
02   ...
03 }
04  
05 function log(a,b,c) {
06   ...
07 }
08  
09 log(a); // вызовется первая функция
10 log(a,b,c); // вызовется вторая функция

 

Это называется «полиморфизмом функций» или «перегрузкой функций». В JavaScript ничего подобного нет.

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

В примере выше второе объявление log просто переопределит первое.

 

Доступ к «лишним» аргументам

Как получить значения аргументов, которых нет в списке параметров?

Доступ к ним осуществляется через «псевдо-массив» arguments.

Он содержит список аргументов по номерам: arguments[0]arguments[1]…, а также свойство length.

Например, выведем список всех аргументов:

 

   
1 function sayHi() {
2   for (var i=0; i<arguments.length; i++) {
3     alert("Привет, " + arguments[i]);
4   }
5 }
6   
7 sayHi("Винни""Пятачок");  // 'Привет, Винни', 'Привет, Пятачок'

 

Все параметры находятся в arguments, даже если они есть в списке. Код выше сработал бы также, будь функция объявлена sayHi(a,b,c).

 

Связь между arguments и параметрами

В старом стандарте JavaScript псевдо-массив arguments и переменные-параметры ссылаются на одни и те же значения.

В результате изменения arguments влияют на параметры и наоборот.

Например:

 

   
1 function f(x) {
2   arguments[0] = 5; // меняет переменную x
3   alert(x); // 5
4 }
5  
6 f(1);

 

Наоборот:

 

   
1 function f(x) {
2   x = 5;
3   alert(arguments[0]); // 5, обновленный x
4 }
5  
6 f(1);

 

В современной редакции стандарта это поведение изменено. Аргументы отделены от локальных переменных:

 

   
1 function f(x) {
2   "use strict"// для браузеров с поддержкой строгого режима
3  
4   arguments[0] = 5;
5   alert(x); // не 5, а 1! Переменная "отвязана" от arguments
6 }
7  
8 f(1);

 

Если вы не используете строгий режим, то чтобы переменные не менялись «неожиданно», рекомендуется никогда не изменять arguments.

 

 

Частая ошибка новичков — попытка применить методы Array к arguments. Об этом говорит сайт https://intellect.icu . Это невозможно:

 

   
1 function sayHi() {
2   var a = arguments.shift(); // ошибка! нет такого метода!
3 }
4  
5 sayHi(1);

 

Дело в том, что arguments — это не массив Array.

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

Впрочем, никто не мешает сделать обычный массив из arguments:

   
1 var args = [];
2 for(var i=0; i<arguments.length; i++) {
3   args[i] = arguments[i];
4 }

 

 

Пример использования: copy(dst, src1,...)

Иногда встает задача — скопировать в существующий объект свойства из одного или нескольких других.

Напишем для этого функцию copy. Она будет работать с любым числом аргументов, благодаря использованию arguments.

Синтаксис:

copy(dst, src1, src2…)
Копирует свойства из объектов src1, src2,... в объект dst. Возвращает получившийся объект.

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

  • Для добавления свойств в объект user:

     

    1 var user = {
    2   name: "Вася",
    3 };
    4  
    5 // добавить свойства
    6 copy(user, {
    7   age: 25,
    8   surname:"Петров"
    9 });
    Использование copy позволяет сократить код, который потребовался бы для ручного копирования свойств:
    user.age = ...
    user.surname = ...
    ...
    Объект user пишется только один раз, и общий смысл кода более ясен.

     

  • Для создания копии объекта user:

     

    // скопирует все свойства в пустой объект
    var userClone = copy({}, user);
    Такой «клон» объекта может пригодиться там, где мы хотим изменять его свойства, при этом не трогая исходный объект user. В нашей реализации мы будем копировать только свойства первого уровня, то есть вложенные объекты не обрабатываются. Впрочем, ее можно расширить.

     

Теперь перейдем к реализации.

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

 

1 function copy(dst) {
2   for (var i=1; i<arguments.length; i++) {
3     var obj = arguments[i];
4     for (var key in obj) {
5       dst[key] = obj[key];
6     }
7   }
8   return dst;
9 }

 

При желании, такое копирование можно реализовать рекурсивно.

arguments.callee и arguments.callee.caller

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

arguments.callee

Свойство arguments.callee содержит ссылку на функцию, которая выполняется в данный момент.

Это свойство устарело. Современная спецификация рекомендует использоватьименованные функциональные выражения (NFE).

Браузеры могут более эффективно оптимизировать код, если arguments.callee не используется.

Тем не менее, свойство arguments.callee зачастую удобнее, так как функцию с ним можно переименовывать как угодно и не надо менять ничего внутри. Кроме того, NFE некорректно работают в IE<9.

 

Например:

 

   
1 function f() {
2   alert( arguments.callee === f); // true
3 }
4  
5 f();

 

Зачем нужно делать какое-то свойство callee, если можно использовать просто f? Чтобы это понять, рассмотрим несколько другой пример.

В JavaScript есть встроенная функция setTimeout(func, ms), которая вызывает func через msмиллисекунд, например:

 

   
1 // выведет 1 через 1000 ms (1 секунда)
2 setTimeout( function() { alert(1) }, 1000);

 

Функция, которую вызывает setTimeout, объявлена как Function Expression, без имени.

А что если хочется из самой функции вызвать себя еще раз? По имени-то обратиться нельзя. Как раз для таких случаев и придуман arguments.callee, который гарантирует обращение изнутри функции к самой себе.

То есть, рекурсивный вызов будет выглядеть так:

 

   
1 setTimeout( 
2   function() {
3     alert(1);
4     arguments.callee(); // вызвать себя
5   },
6   1000
7 )

 

Аргументы можно передавать в arguments.callee() так же, как в обычную функцию.

Пример с факториалом:

1 // factorial(n) = n*factorial(n-1)
2 var factorial = function(n) { 
3   return n==1 ? 1 : n*arguments.callee(n-1);
4 }
Функция factorial не использует свое имя внутри , поэтому рекурсивные вызовы будут идти правильно, даже если функция «уехала» в другую переменную.

 

 

   
1 // factorial(n) = n*factorial(n-1)
2 var factorial = function(n) { 
3   return n==1 ? 1 : n*arguments.callee(n-1);
4 }
5  
6 var g = factorial;
7 factorial = 0; // функция переместилась в переменную g
8  
9 alert( g(5) ); // 120, работает!

 

Рекомендованной альтернативой arguments.callee являются именованные функциональные выражения.

arguments.callee.caller

Свойство arguments.callee.caller хранит ссылку на функцию, которая вызвала данную.

Это свойство устарело, аналогично arguments.callee.

Также существует похожее свойство arguments.caller (без callee). Оно не кросс-браузерное, не используйте его. Свойство arguments.callee.caller поддерживается везде.

 

Например:

 

   
01 f1();
02  
03 function f1() {
04   alert(arguments.callee.caller); // null
05   f2();
06 }
07  
08 function f2() {
09   alert(arguments.callee.caller); // f1, функция вызвавшая меня
10 }

 

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

Почему callee и caller устарели?

В современном стандарте эти свойства объявлены устаревшими, и использовать их не рекомендуется. Хотя де-факто они используются хотя бы потому, что IE до 9 версии не поддерживает Named Function Expression так, как должен.

Причина отказа от этих свойств простая — интерпретатор может оптимизировать JavaScript более эффективно. Тем более, что для arguments.callee есть замена — NFE.

 

Важность: 5

Как в функции отличить отсутствующий аргумент от undefined?

1 function f(x) {
2   // ..ваш код..
3   // выведите 1, если первый аргумент есть, и 0 - если нет
4 }
5  
6 f(undefined); // 1
7 f(); // 0

 

Решение

Узнать количество реально переданных аргументов можно по значениюarguments.length:

 

   
1 function f(x) {
2   alert(arguments.length ? 1 : 0);
3 }
4  
5 f(undefined);
6 f();

 

[Открыть задачу в новом окне]

 

 

Важность: 5

Напишите функцию sum(...), которая возвращает сумму всех своих аргументов:

 

1 sum() = 0
2 sum(1) = 1
3 sum(1, 2) = 3
4 sum(1, 2 ,3) = 6
5 sum(1, 2, 3, 4) = 10

 

Решение

 

   
01 function sum() {
02   var result = 0;
03  
04   for(var i=0; i<arguments.length; i++) {
05     result += arguments[i];
06   }
07  
08   return result;
09 }
10  
11 alert( sum() ); // 0
12 alert( sum(1) ); // 1
13 alert( sum(1, 2) ); // 3
14 alert( sum(1, 2, 3) ); // 6
15 alert( sum(1, 2, 3, 4) ); // 10

 

К сожалению, в одной статье не просто дать все знания про псевдо-массив arguments. Но я - старался. Если ты проявишь интерес к раскрытию подробностей,я обязательно напишу продолжение! Надеюсь, что теперь ты понял что такое псевдо-массив arguments и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)

создано: 2014-10-07
обновлено: 2021-03-13
132773



Рейтиг 9 of 10. count vote: 2
Вы довольны ?:


Поделиться:

Найди готовое или заработай

С нашими удобными сервисами без комиссии*

Как это работает? | Узнать цену?

Найти исполнителя
$0 / весь год.
  • У вас есть задание, но нет времени его делать
  • Вы хотите найти профессионала для выплнения задания
  • Возможно примерение функции гаранта на сделку
  • Приорететная поддержка
  • идеально подходит для студентов, у которых нет времени для решения заданий
Готовое решение
$0 / весь год.
  • Вы можите продать(исполнителем) или купить(заказчиком) готовое решение
  • Вам предоставят готовое решение
  • Будет предоставлено в минимальные сроки т.к. задание уже готовое
  • Вы получите базовую гарантию 8 дней
  • Вы можете заработать на материалах
  • подходит как для студентов так и для преподавателей
Я исполнитель
$0 / весь год.
  • Вы профессионал своего дела
  • У вас есть опыт и желание зарабатывать
  • Вы хотите помочь в решении задач или написании работ
  • Возможно примерение функции гаранта на сделку
  • подходит для опытных студентов так и для преподавателей



Комментарии


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

Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)

Термины: Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)