On a deeper understanding about proto and prototype

Last a few days, I just looked through some basic rules about prototype and __proto__. But today when I learnt how to implement the function call() by myself, I found that there’s something unclear.

1
2
3
4
5
6
7
8
Function.prototype.myCall = function(ctx) {
ctx = ctx || window;
ctx.fn = this;
let args = [...arguments].slice(1);
let result = ctx.fn(...args);
delete ctx.fn;
return result;
}

How to understand the third line? What does this refer to?

First, let’s recall how we use the function myCall.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Function.prototype.myCall = function(ctx) {
ctx = ctx || window;
ctx.fn = this;
let args = [...arguments].slice(1)
let result = ctx.fn(...args)
delete ctx.fn
return result;
}

function a(x,y) {
return x+y;
}

const obj = {
m: 1,
n: 2,
}

a.myCall(obj, 3,5)
  1. a is a function
  2. a uses its method myCall.

Wait. As far as I’m concerned, only Object can has a method. But how could a function use a method?

So I looked through some information, and a picture can conclude it well.

proto

  1. Everything in JS is Object. Function is an object, Function.prototype is an object. So they all share the same feature: they have a property: __proto__, which is a pointer to its constructor’s prototype.
  2. Function is a special object. Including general properties, it has an extra property: prototype, which has a property named constructor which is the Function itself.

So it’s easy for us to understand:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Function.prototype.myCall = function(ctx) {
ctx = ctx || window;
ctx.fn = this;
console.log(this===a)//true;
let args = [...arguments].slice(1)
let result = ctx.fn(...args)
delete ctx.fn
return result;
}

function a(x,y) {
return x+y;
}
console.log(a instanceof Function)//true

const obj = {
m: 1,
n: 2,
}

console.log(a.prototype.constructor===a)//true
console.log(a.__proto__===Function.prototype)//true
console.log(a.prototype.__proto__===Object.prototype)//true

a.myCall(obj, 3,5)

So how do we understand the total process of the code?

First we define a method myCall for Function.prototype, then we define a function a, which is inherited from Function.prototype.

In the last line, we make the function a (also an object) call the method myCall. First it look up in a‘s properties, but cannot match, so it backtracks to a.__proto__ AKA Function.prototype. So it finally finds the method, and this refers to the object & function a.

Finally we revise the basic knowledge of prototype chain.

Object.prototype(top of the prototype chain)

Function.prototype inherited from Object.prototype

Function and Object inherited from Function.prototype.

There are some thoughts on the topic which is interestring.

从探究Function.proto===Function.prototype过程中的一些收获

Comments