Что такое функция .call(), выполняемая в этом выражении Javascript?

Я активно изучаю javascript, и я натолкнулся на следующее утверждение:

Object.prototype.toString.call([]); 

И я не знаю, что это значит или что он делает.

У меня есть смутное понимание .call, поскольку он позволяет вам вызвать метод в контексте другого объекта (я думаю), но мне трудно понять, какую роль выполняет функция .call() играя в вышеуказанном заявлении. Поэтому мне было интересно, может ли кто-нибудь объяснить, что здесь делает .call()?

Спасибо!!

Ответ 1

Метод call устанавливает значение this вызываемой функции для объекта, переданного как первый аргумент, в вашем примере выполняется метод Object.prototype.toString объекта Array.

Объекты массива имеют свой собственный метод toString (Array.prototype.toString), который затеняет значение из Object.prototype, если вы вызываете [].toString();, будет вызван метод в Array.prototype.

Например:

function test() {
  alert(this);
}
test.call("Hello"); // alerts "Hello"

Другой пример:

var alice = {
  firstName: 'Alice',
  lastName: 'Foo',
  getName: function () {
    return this.firstName + ' ' + this.lastName;
  }
};

var bob = {
  firstName: 'Bob',
  lastName: 'Bar',
};

alice.getName.call(bob); // "Bob Bar"

В приведенном выше примере мы используем метод Alice getName для объекта Bob, значение this указывает на bob, поэтому метод работает так же, как если бы он был определен для второго объекта.

Теперь поговорим о методе Object.prototype.toString. Все собственные объекты в JavaScript содержат внутреннее свойство, называемое [[Class]]. Это свойство содержит строковое значение, которое представляет определенную спецификацией классификацию объекта, возможные значения для собственных объектов:

  • "Object"
  • "Array"
  • "Function"
  • "Date"
  • "RegExp"
  • "String"
  • "Number"
  • "Boolean"
  • "Error" для объектов ошибок, таких как экземпляры ReferenceError, TypeError, SyntaxError, Error и т.д.
  • "Math" для глобального объекта Math
  • "JSON" для глобального объекта JSON, определенного в ECMAScript 5th Ed. спецификации.
  • "Arguments" для объекта arguments (также введенного в спецификации ES5).
  • "null" (введено всего пару дней назад в ошибках ES5)
  • "undefined"

Как я уже говорил, это свойство является внутренним, нет возможности изменить его, спецификация не предоставляет никакого оператора или встроенной функции для этого, и единственный способ получить доступ к его значению - через Object.prototype.toString.

Этот метод возвращает строку, образованную:

"[object " + this.[[Class]] + "]"

Только для пояснительных целей, так как [[Class]] не может быть доступен напрямую.

Например:

Object.prototype.toString.call([]);       // "[object Array]"
Object.prototype.toString.call(/foo/);    // "[object RegExp]"
Object.prototype.toString.call({});       // "[object Object]"
Object.prototype.toString.call(new Date); // "[object Date]"
// etc...

Это действительно полезно для безопасного определения типа объекта, для обнаружения объектов массива, наиболее широко используемого метода:

function isArray(obj) {
  return Object.prototype.toString.call(obj) == '[object Array]';
}

Может возникнуть соблазн использовать оператор instanceof, но это приведет к проблемам, если вы работаете в средах с несколькими кадрами, потому что объект массива, созданный на одном кадре, не будет instanceof Array конструктор другого.

Вышеуказанный метод будет работать без каких-либо проблем, поскольку объект будет содержать значение его внутреннего свойства [[Class]].

См. также:

Ответ 2

Потому что toString в основном не вызывается с параметром, а не toString('foo'), но bar.toString(). Здесь call пригодится.

Различные toString s

Я говорю "в основном", потому что существуют разные toString s:

  • Object.prototype.toString возвращает строку, представляющую объект
  • Array.prototype.toString возвращает строку, представляющую указанный массив и его элементы
  • Number.prototype.toString возвращает строку, представляющую указанный объект Number
  • String.prototype.toString возвращает строку, представляющую указанный объект String
  • Function.prototype.toString возвращает строку, представляющую исходный код функции

Экземпляр использования отдельно

(new Object()).toString();                // "[object Object]"
["foo", "bar"].toString();                // "foo,bar"
(6).toString(2);                          // "110"
("meow").toString();                      // "meow"
(function(){return 'x';}).toString()      // "function (){return 'x';}"

Хотя весь объект прототипически наследуется от Object, последние не наследуют toString от Object toString, а это значит, что все они разные и имеют разные виды использования. Чтобы указать тип объекта, Object.prototype.toString является полезным, так как он возвращает тип:

Каждый объект имеет метод toString(), который автоматически вызывается, когда объект должен быть представлен как текстовое значение или когда объект ссылается так, как ожидается строка. По умолчанию метод toString() наследуется каждым объектом, сгенерированным из Object. Если этот метод не переопределяется в пользовательском объекте, toString() возвращает "[тип объекта]", где type - тип объекта.

Вызов

Обратите внимание, что среди них единственный, который принимает параметр, - это Number.prototype.toString, а для указания базы номера исхода. Поэтому, чтобы вызывать Object.prototype.toString для массивов, чисел и другого объекта, который имеет свой собственный метод toString, вам нужно call указать this:

Object.prototype.toString.call(Math);         // [object Math]
Object.prototype.toString.call(new Date);     // [object Date]
Object.prototype.toString.call(new String);   // [object String]
Object.prototype.toString.call(Math);         // [object Math]

// Since JavaScript 1.8.5
Object.prototype.toString.call(undefined);    // [object Undefined]
Object.prototype.toString.call(null);         // [object Null]