звони, звони. звони, звони. звони. звони, ты можешь не понять этот сумасшедший звонок

внешний интерфейс JavaScript
звони, звони. звони, звони. звони. звони, ты можешь не понять этот сумасшедший звонок

Это 24-й день моего участия в августовском испытании обновлений. Узнайте подробности события:Испытание августовского обновления.

предисловие

Function.prototype.callЯ думаю, что все чувствуют себя знакомыми,Почерк в порядке! !
Прежде чем подтвердить эту проблему, сначала посмотрите на3000 слов, и я не написал Function.prototype.call,

После прочтения вы чувствуете себя хорошо, тогда посмотрите на другой вопрос:
Пожалуйста, спросите следующий вывод

function a(){ 
    console.log(this,'a')
};
function b(){
    console.log(this,'b')
}
a.call.call(b,'b')  

Если вы также четко знаете, результат, извините, босс, извините, я был неправ!

Происхождение этой статьи:
Мой друг добавил меня в WeChat и задал мне этот вопрос в приватном чате.После изучения, я снова попросил совета.апо.
Я думал, что это было интересно, поэтому я хотел поделиться им со всеми вами!

результат

Результаты таковы: Удивление или удивление, или спокойствие?

String {"b"} "b"

Взгляните на следующий код: 2, 3, 4 и более вызовов, вывод будетString {"b"} "b"

function a(){ 
    console.log(this,'a')
};
function b(){
    console.log(this,'b')
}
a.call.call(b,'b')  // String {"b"} "b"
a.call.call.call(b,'b')   // String {"b"} "b"
a.call.call.call.call(b,'b')  // String {"b"} "b"

После прочтения вышеизложенного должно быть три вопроса?

  1. почему называетсяbфункция
  2. ЗачемthisдаString {"b"}
  3. почему 2, 3, 4callтот же результат

В заключение:
Более двух вызовов, напримерcall.call(b, 'b'), вы можете просто понять, что сb.call('b')

анализировать

почему 2, 3, 4callтот же результат

a.call(b)Последний звонокa,
a.call.call(b), который в итоге называетсяa.call
a.call.call.call(b), который наконец выполняетсяa.call.call

Взгляните на эталонные отношения

a.call === Function.protype.call  // true
a.call === a.call.call  // true
a.call === a.call.call.call  // true

На основании вышеизложенноговоплощать в жизньанализировать:
a.callназываетсяa
a.call.callа такжеa.call.call.callРазницы по сути нет, оба называютсяFunction.prototype.call.

почему 2, 3, 4callРезультат такой же, до сих порправдаохватывать

почему называетсяbфункция

Глядя на суть, надо вернуться к оригиналу, стандарт ЕС правFuntion.prototye.callописание

Function.prototype.call (thisArg , ...args)

When the call method is called on an object func with argument, thisArg and zero or more args, the following steps are taken:

  1. If IsCallable(func) is false, throw a TypeError exception.
  2. Let argList be an empty List.
  3. If this method was called with more than one argument then in left to right order, starting with the second argument, append each argument as the last element of argList.
  4. Perform PrepareForTailCall().
  5. Return Call(functhisArgargList).

перевести на китайский

  1. Если не вызывается, сгенерируйте исключение
  2. Подготовьте пустую переменную массива argList
  3. Добавляйте переменные после первой в argList по порядку
  4. вернутьCall(functhisArgargList)результат

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

Собственно тут я и перестал думать:

a is a function, then what a.call.call really do?Пояснение к статье, упомянутойBound Function Exotic Objects, МДНFunction.prototype.bindТакже упоминается:

The bind() function creates a new bound function, which is an exotic function object (a term from ECMAScript 2015) that wraps the original function object. Calling the bound function generally results in the execution of its wrapped function.

Function.prototype.callНаоборот, не упоминается! ! ! Но он не проверяет, генерируется ли он во время вызывающего процесса.

Difference between Function.call, Function.prototype.call, Function.prototype.call.call and Function.prototype.call.call.callЯ думаю, что объяснение более разумно.

function my(p) { console.log(p) }
Function.prototype.call.call(my, this, "Hello"); // output 'Hello'

Function.prototype.call.call(my, this, "Hello"); means:

Use my as this argument (the function context) for the function that was called. In this case Function.prototype.call was called.

So, Function.prototype.call would be called with my as its context. Which basically means - it would be the function to be invoked.

It would be called with the following arguments: (this, "Hello"), where this is the context to be set inside the function to be called (in this case it's my), and the only argument to be passed is "Hello" string.

Выделять:
So, Function.prototype.call would be called with my as its context. Which basically means - it would be the function to be invoked.

It would be called with the following arguments: (this, "Hello"), where this is the context to be set inside the function to be called (in this case it's my), and the only argument to be passed is "Hello" string

переводить:
Function.prototype.call.call(my, this, "Hello")означает: использоватьmyвызывается как контекстFunction.prototype.call, то естьmyэто функция, которая в конечном итоге вызывается.

myс этими(this, "Hello")называется,thisкак контекст вызываемой функции, здесь какmyКонтекст функции, единственный передаваемый параметр — это строка «hello».

Основываясь на этом понимании, давайте просто проверим, что это действительно такой внешний вид.

// case 1:
function my(p) { console.log(p) }
Function.prototype.call.call(my, this, "Hello"); // output 'Hello'

// case 2:
function a(){ 
    console.log(this,'a')
};
function b(){
    console.log(this,'b')
}
a.call.call(b,'b')  // String {"b"} "b"

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

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

ЗачемthisдаString {"b"}

В анализе в предыдущем разделе я намеренно не учелFunction.prototype.callдваnote

NOTE 1: The thisArg value is passed without modification as the this value. This is a change from Edition 3, where an undefined or null thisArg is replaced with the global object and ToObject is applied to all other values and that result is passed as the this value. Even though the thisArg is passed without modification, non-strict functions still perform these transformations upon entry to the function.

NOTE 2: If func is an arrow function or a bound function then the thisArg will be ignored by the function [[Call]] in step 5.

Обратите внимание на это предложение:

This is a change from Edition 3, where an undefined or null thisArg is replaced with the global object and ToObject is applied to all other values and that result is passed as the this value

Два момента:

  1. еслиthisArgдаundefinedилиnull, будет заменен глобальным объектом

Предпосылка вот чтонестрогий режим

"use strict"

function a(m){
    console.log(this, m);  // undefined, 1
}

a.call(undefined, 1)
  1. Все остальные типы будут вызыватьToObjectдля преобразования

такнестрогий режимВниз,thisЭто должен быть объект, см. следующий код:

Object('b') // String {"b"}

заметка 2ToObjectэто ответ

Вот почемуthisдаSting(b)Это также верно

Универсальный метод вызова функции

на основеFunction.prototype.call.callфункция, мы можем инкапсулировать универсальный метод вызова функции

var call = Function.prototype.call.call.bind(Function.prototype.call);

Пример

var person = {
    hello() { 
        console.log('hello', this.name) 
    }
}

call(person.hello, {"name": "tom"})  // hello tom

напиши в конце

Если вы считаете, что это хорошо, ваши лайки и комментарии — самая большая мотивация для меня двигаться дальше.

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

Цитировать

sec-function.prototype.call
Bound Function Exotic Objects
Function.prototype.bind a is a function, then what a.call.call really do?
Difference between Function.call, Function.prototype.call, Function.prototype.call.call and Function.prototype.call.call.call
Javascript Function.prototype.call()
Can't use Function.prototype.call directly