This is the 24th day of my participation in the August More Text Challenge.

preface

Function.prototype.call I think you all think you are familiar with it and can write it by hand!! Before you confirm this question, first have a look at three thousand words.

After reading, you feel OK, then look at a problem: please ask the following output result

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

If, you also clearly know, the result, sorry, big guy, disturb, I was wrong!

The origin of this article: a digger added me to wechat and asked me this question in private chat. After researching it, he asked Po Ge. Feel very interesting, then share with everyone!

The results of

The result: Surprise or surprise, or calm?

String {"b"} "b"
Copy the code

For two, three, four, or more calls, the output will be 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"
Copy the code

After reading the above, there should be three questions, right?

  1. Why is it calledbfunction
  2. whythisisString {"b"}
  3. Why two, three, fourcallWith the same results.

Call (b, ‘b’); call(b, ‘b’);

Analysis of the

Why two, three, fourcallWith the same results.

A.call (b) is finally called by a, a.call.call(b), which is finally called by a.call.call.call(b), which is finally executed by A.call.call

Look at the reference relationship

a.call === Function.protype.call  // true
a.call === a.call.call  // true
a.call === a.call.call.call  // true
Copy the code

A. call.call (function.prototype. call); function.prototype. call

Why are the results of 2, 3 and 4 calls the same and the truth is already there

Why is it calledbfunction

Look at the essence will be back to nature, ES standard for Funtion. Prototye. Call description

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(func.thisArg.argList).

Translate it into Chinese

  1. If not, throw an exception
  2. Prepare an argList empty array variable
  3. Variables after the first are added to argList in order
  4. returnCall(func.thisArg.argListThe result of)

Instead of an abstract definition, Call is actually a Call to the [[Call]] method inside the function, and it doesn’t reveal much useful information.

In fact, I’ve stopped thinking here:

a is a function, then what a.call.call really do? Bind (MDN, function.prototype.bind) : “I have Bound Function Exotic Objects.

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 is not mentioned!! But do not check that there is a build during the call.

Difference between Function.call, Function.prototype.call, Function. The prototype. The call. The call and the Function. The prototype. The call. The call. The call is to explain, I think it is more reasonable

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

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.

Highlight: 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

Translation: the Function prototype. Call. The call (my, this, “Hello”), said: in my as the context to invoke the Function. The prototype. The call, that is to say my is ultimately the called Function.

My is called with these (this, “Hello”), this as the context of the called function, here as the context of my function, and the only argument passed is the “Hello” string.

With this understanding, let’s just verify that this is indeed the case

// 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"
Copy the code

Why is it calledbDelta function, that’s the truth.

In fact, I still can not be too relieved, but this explanation is acceptable, the appearance is correct, expect digg friends to have a more reasonable, more detailed answer.

whythisisString {"b"}

I intentionally left out two notes for function.prototype. call in the previous section

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.

Notice this sentence:

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

Two points:

  1. ifthisArgisundefinedornull, will be replaced with global Object

The premise here is non-strict mode

"use strict"

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

a.call(undefined.1)
Copy the code
  1. For all other types, ToObject is called for conversion

So in non-strict mode, this must be an object, look at the following code:

Object('b') // String {"b"}
Copy the code

ToObject of Note2 is the answer

That’s it. WhythisisSting(b)That’s true, too

Universal function call method

. Based on the Function prototype. Call. The characteristics of the call, we can encapsulate a universal method of Function calls

var call = Function.prototype.call.call.bind(Function.prototype.call);
Copy the code

The sample

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

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

Write in the last

If you think it is good, your likes and comments are the biggest motivation for me to move forward.

Technical group please come here. Or add my wechat Dirge-Cloud and learn together.

reference

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