Зачем вам передавать "null" на "apply" или "call"?

Согласно этой ссылке JavaScript:

Значение null - это литерал JavaScript, представляющий значение NULL или "пустое" значение, т.е. значение объекта отсутствует. Это одно из примитивных значений JavaScript.

function getMax(arr){
  return Math.max.apply(null, arr);  
}

Не было явной передачи ключевого слова this яснее, или, по крайней мере, более удобным для чтения? Опять же, в этот момент я не могу понять, почему вы используете null.

Ответ 1

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

Что делает метод apply?

Метод apply() вызывает функцию с заданным значением this и arguments, представленный как массив (или подобный массиву объект).

fun.apply(thisArg, [argsArray])

thisArg

Значимость этого обеспечила для удовольствия. Обратите внимание, что это может не быть фактическим значением, которое видит метод: если метод является функцией в нестрогого режима, null и undefined будут заменены на глобальный объект и примитивные значения будут помещены в поле.

Дополнительную документацию можно найти здесь.

Ответ 2

Зачем вам передавать "null" на "apply" или "call"?

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

Явным образом не передавал бы ключевое слово this? Или по крайней мере более читаемый человеком. И снова в этот момент я могу не понять, почему вы должны использовать null.

В вашем конкретном случае, вероятно, лучше всего передать объект Math:

function getMax(arr){
  return Math.max.apply(Math, arr);  
}

В то время как выясняется, что не имеет значения, что вы передаете в качестве первого аргумента для Math.max.apply(...) (только из-за особенностей реализации Math.max()), передача Math устанавливает указатель this на точный то же самое, что было бы установлено, когда вы обычно вызываете его как Math.max(1,2,3), так что это самый безопасный вариант, так как вы лучше всего имитируете обычный вызов Math.max().

Зачем вам передавать "null" на "apply" или "call"?

Вот еще несколько деталей... При использовании .call() или .apply(), null может быть передано, когда у вас нет определенного значения, которое вы хотите установить для указателя this, и вы знаете, что функция вы вызываете, не ожидаете, что this имеет какое-либо конкретное значение (например, он не использует this в своей реализации).

Примечание. Использование null с .apply() или .call() обычно выполняется только с функциями, которые являются методами только для пространств имен, а не объектно-ориентированными. Другими словами, функция max() является методом объекта Math только из-за причин, связанных с именами, а не потому, что объект Math имеет данные экземпляра, к которому должен обращаться метод .max().


Если вы делали это так:

   function foo() {
       this.multiplier = 1;
   }

   foo.prototype.setMultiplier = function(val) {
       this.multiplier = val;
   }

   foo.prototype.weightNumbers = function() {
       var sum = 0;
       for (var i = 0; i < arguments.length; i++) {
           sum += (arguments[i] * this.multiplier);
       }
       return sum / arguments.length;
   }

   var x = new foo();
   x.setMultiplier(3);
   var numbers = [1, 2, 3]
   console.log(x.weightNumbers.apply(x, numbers));

Когда метод, которому вы вызываете .apply() on, должен получить доступ к данным экземпляра, тогда вы ДОЛЖНЫ передать соответствующий объект в качестве первого аргумента, чтобы метод имел правильный указатель this для выполнения своей работы, как ожидалось.

Ответ 3

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

Что такое null в JavaScript?

Значение null является литералом (не может быть свойство глобального объекта, такого как undefined). Это одно из базовых значений JavaScript.

В API-интерфейсах нуль часто получается на месте, где можно ожидать объекта, но объект не имеет значения.

fun.apply(thisArg, [argsArray])

thisArg. Значение этого параметра для развлечения. Обратите внимание, что это может быть не фактическое значение, которое видит метод: если метод является функцией в коде нестрого режима, то null и undefined будут заменены глобальным объектом, а примитивные значения будут помещены в бокс.

argsArray: объект, похожий на массив, указывающий аргументы, с которыми нужно вызвать fun, или null или undefined, если аргументы не должны предоставляться функции. Начиная с ECMAScript 5, эти аргументы могут быть общим объектом типа массива, а не массивом. См. Ниже информацию о совместимости браузера.

Если вы используете "строгий режим", тогда желательно передать это или Math в качестве параметра.

Ответ 4

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

Поскольку связанные функции не могут быть восстановлены, и они всегда будут вызываться с thisArg который был передан в bind, нет смысла передавать thisArg в call или apply. Из источника:

Функция bind() создает новую связанную функцию (BF).... Когда вызывается связанная функция, она вызывает внутренний метод [[Call]] для [[BoundTargetFunction]] со следующими аргументами Call(boundThis, args).

Вот пример:

class C {
  constructor() {
    this.a = 1;
  }
}

function f(n, m) {
  console.log(this.a + n + m);
}

let c = new C();
var boundF = f.bind(c, 2); // the context 'c' is now bound to f
boundF.apply(null, [3]); // no reason to supply any context, since we know it going to be 'c'

Ответ 5

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

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

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

EventManager.raise('some:event-name', arg1, arg2, arg3, ..);

... и чтобы все зарегистрированные обработчики для этого события вызывались с этим списком аргументов (arg1, arg2 и т.д.). Таким образом, в функции повышения она проходит через обработчики, которые зарегистрированы для этого имени события, и вызывает их, передавая все переданные аргументы, кроме имени события, например:

var args = [];
Array.prototype.push.apply(args, arguments);
args.shift();
for (var l in listeners) {
    var listener = listeners[l];
    listener.callback.apply(listener.context, args);
}

Когда вызывается зарегистрированный обработчик (listener.callback), apply применяется для передачи переменного числа аргументов. Здесь я позволил слушателю предоставлять этот контекст для его обработчика события, когда определитель слушателя определен, но этот контекст может быть не определен или он может быть нулевым, и это совершенно нормально.

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