Javascript Function.prototype.call()

旧巷老猫 提交于 2019-12-17 20:30:25

问题


I read some article and it said the following 2 line are doing the same thing.

fn.call(thisValue);
Function.prototype.call.call(fn, thisValue);

For line 1, my understanding is that every function object in Javascript do have a the method call inherited from the Function.prototype and what call method does is to have the this keyword inside the function definition of fn to be thisValue(the first parameter I passed in the call method. fn is a function so what I am doing in fn.call(thisValue) is just invoking fn and set the this keyword inside the function to be thisValue.

But For line 2, I don't get it. Can someone help to explain it what the hack the line 2 is doing.


回答1:


Let's start with this setup:

function fn() { console.log(this); }
var thisvalue = {fn: fn};

Now you surely understand that thisvalue.fn() is a method call, and sets the logged this value to the thisvalue object.

Next, you seem to know that fn.call(thisvalue) does exactly the same call. Alternatively, we could write (thisvalue.fn).call(thisvalue) (parentheses just for structure, could be omitted) as thisvalue.fn === fn:

thisvalue.fn(…); // is equivalent to
(thisvalue.fn).call(thisvalue, …); // or:
(fn).call(thisvalue, …);

OK, but fn.call(…) is just a method call as well - the call method of functions is called on the fn function.
It can be accessed as such because all function objects inherit this .call property from Function.prototype - it's not an own property like .fn on the thisvalue object. However, fn.call === Function.prototype.call is the same as thisvalue.fn === fn.

Now, we can rewrite that method call of .call as an explicit invocation with .call():

fn.call(thisvalue); // is equivalent to
(fn.call).call(fn, thisvalue); // or:
(Function.protoype.call).call(fn, thisvalue);

I hope you spot the pattern and can now explain why the following work as well:

Function.prototype.call.call.call(Function.prototype.call, fn, thisvalue);
var call = Function.prototype.call; call.call(call, fn, thisvalue);

Breaking this down is left as an exercise to the reader :-)




回答2:


Since I ended up here trying to understand this question, I'm gonna post my answer here as well.

Let's start with this:

function fn() { console.log(this); }
fn.a = function(){console.log(this)} // "this" is fn because of the . when calling
fn.a() // function fn() { console.log(this); }

So let's dig deeper and try to reimplement the call function:

  Function.prototype.fakeCall = function () {
    // taking the arguments after the first one
    let arr = Array.prototype.slice.call(arguments, 1);
    try{
       return this.apply(arguments[0], arr);
    }catch(e){}
  }

  function a(ar){ console.log(ar + this.name) };
  let obj = {name : "thierry"};
  // a.fakeCall( obj, 'hi ')

  Function.fakeCall.fakeCall(a, obj, 'hi ');

Thus when we do this: Function.prototype.fakeCall.fakeCall(a, obj, 'hi ')

what happens is, on the first run we have:

  1. arr = [ obj, 'hi ']
  2. this = Function.fakeCall

so we end up with Function.fakeCall.apply(a, [ obj, 'hi ']);

Then on the second run we have

  1. arr = ['hi']
  2. this = a

so we end up with a.apply(obj, ['hi']) which is the same as a.call(obj, 'hi');

source



来源:https://stackoverflow.com/questions/31074664/javascript-function-prototype-call

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!