Writing in the front

In the process of the interview, I believe that many friends have experienced some of the best not to its sister’s questions, or difficult problems, or strange questions, or the topic. Today let’s look at a relatively partial, but actually very basic interview question. A friend of mine met this question six months ago when he went to an interview for bytedance’s Guangzhou branch. He said that he would not do it at that time, and after coming back to share.

Knowledge preparation

The function.prototype. call method (Function#call) is used to specify this object, or, more informally, Is used to let an object borrow a method from another object. For example, we have an array method called Array#push, and then we invent a false array (which is an object with a length attribute). If we want to borrow the push method of the true array to add elements, we might write the following code:

const arrayLike = {
   length: 0
}
[].push.call(arrayLike, 1)
console.log(arrayLike); // {0: 1, lenght: 1}
Copy the code

The fun #call method is used in line 4. Because it allows an object that does not own a method to borrow the method of another object to call, so in many libraries and framework source code is very high.

Which leads to the problem

OK, that’s the end of Function#call. What question did the interviewer ask in Toutiao make my friend lose his mind?

Here’s the title:

The following code should execute normally:

const arrayLike = {
   length: 0
}
[].push.call(arrayLike, 1);
console.log(arrayLike); // {0: 1, lenght: 1}
Copy the code

[].push. Call = [].push. Call = [].push.

const arrayLike = {
   length: 0
}
const call = [].push.call;
call(arrayLike, 1); 
console.log(arrayLike);
Copy the code

What is the reason for this?

Function#call is assigned to a variable and then called. I haven’t used Function#call before, but my intuition tells me that there is something wrong with this code, so I immediately see the results in the chrome console:

Ah! call is not a function ? Are you kidding me? Use the Typeof operator to verify that it is a function

I really want to swear at this moment, don’t I? Call () : call is not a function; typeof: call is not a function! Are you angry?

To solve the problem

Calm down! Interview encounter do not understand the problem must be calm, if nervous really do not know how to do, can only cold salad. What can calm do? After you have calmed down, try to find ideas from the implementation principles or source code.

Function#myCall is a Function#myCall method.

Function.prototype.myCall = function(context, ... args) { context = context || {}; context.fn = this; const res = context.fn(... args); delete context.fn;return res;
}
Copy the code

Let’s verify myCall’s functionality:

const arrayLike = {
   length: 0
}
[].push.myCall(arrayLike, 1)
console.log(arrayLike); // {0: 1, lenght: 1}
Copy the code

OK, it’s working.

Then, what happens if [].push.myCall is assigned to a variable and then called? Will this be the same as the native call? As follows:

const arrayLike = {
   length: 0
}
const myCall = [].push.myCall;
myCall(arrayLike, 1);
console.log(arrayLike); 
Copy the code

The execution result in Chrome is as follows:

Fn is not a function. From the source code we can see that context.fn is actually this because the source code has the assignment statement context.fn = this. So what is this? It’s window on the browser side, and global on the node side, because they’re not really function. So the call will report an error.

Now you can see why Functio#call cannot be called after being assigned to a variable.

Other environmental

On the other hand, chrome’s “call is not function” error message is very unfriendly, and even contradictory. Because he says that the value of the call variable is not function, whereas typeof detection is function. So the problem itself isn’t really that difficult, but it’s actually misinformed by Chrome’s very unfriendly misinformation.

Let’s take a look at the error messages on other browsers or nodes:

  • IE11 browser

  • Edge browser:

  • The firefox browser

  • The node server

The error message for Node server and Chrome server is the same: call is not a function. This is because they both use the V8 interpreter. Error: this is not a Function object Firefox’s error message is function.prototype. Call called on incompatible undefined.? I had no idea, so I quietly clicked on the right side of the error message and opened the MDN detail page on x.pertotype. Y called on Incompatible Type. For example, Function# call, Function#apply, Function#bind, etc.

To summarize

The same error appears in different browsers but a variety of error messages, you can see that elegant error message is difficult, v8 issue 6513 is dedicated to this. In this issue, someone suggested:

var c = Function.prototype.call; c();
Uncaught TypeError: c is not a function
Copy the code

Should be something like:

c is called with undefined as a context which is not a function
Copy the code

Maybe it would be more elegant to change it to a proposal.

In addition, if we encounter some problems in our daily work or interview, we should not guess out of thin air, but analyze the root of the problem through the essence and principle.

There is another story

The headline is just a joke, if you know how to do this topic may not be in the headline, hahaha. But if you can’t do it, it means your basic skills are not solid enough, and you may not pass the interview.