Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript call() and Prototype - Slice Function

I'm reading the MDN Article on slice in JavaScript. I understand everything except the 2nd example in the section titled Array-Like Objects.

It says we can simplify the first example by making slice our own function as so:

var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);

function list() {
  return slice(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

What I don't understand is how call can come right after prototype on the second line.

I usually see it in the form of Array.prototype.slice.call(arguments) or something of that sort.

I don't understand the flow of the first two lines and how they generate this working slice function.

like image 437
qarthandso Avatar asked Dec 18 '22 16:12

qarthandso


2 Answers

tl;dr:

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

is a short way of writing:

var slice = function(value, start, end) {
  return unboundSlice.call(value, start, end);
};

Let's think about this line for second:

Array.prototype.slice.call(arguments)

.slice is an array method to extract a subset of the array. It operates on the value of this. .call is a method every function has, it lets you set the this value for a function execution. So, the above line lets us execute slice as a method of arguments, without having to mutate arguments itself. We could have done

arguments.slice = Array.prototype.slice;
arguments.slice();

but that is not as clean.

Now looking at

Function.prototype.call.bind(unboundSlice);

As said, .call is a method that every function has. It also operates on this, which is expected to be a function. It calls this and sets the this value of that function to the first argument. You could think of call as being similar to

function call(thisValue, arg1, arg2, ...) {
   return this.apply(thisValue, [arg1, arg2, ...]);
}

Note how it calls this as a function.

.bind is also a method every function has. It returns a new function which has its this value fixed to the first argument you pass in.

Let's consider what the resulting function of call.bind(unboundSlice) would look like:

function boundCall(thisValue, arg1, arg2, ...) {
   return unboundSlice.apply(thisValue, [arg1, arg2, ...]);
}

We simply replaced this with unboundSlice. boundCall will now always call unboundSlice.

like image 91
Felix Kling Avatar answered Jan 06 '23 14:01

Felix Kling


The MDN article for Function.prototype.call() helped me wrap my head around this.

The most simplistic way I can answer:

In javascript, a Function has a method called call. A function is an object, and all objects inherit methods and properties from their prototype.

So your example of Array.prototype.slice.call(arguments) shows you calling the call method on the slice function.

The second line in the code that you are confused about: var slice = Function.prototype.call.bind(unboundSlice); shows the call method belonging to the Function prototype.

Checkout JavaScript Prototypes if you are still confused.

1 Functions are objects.

2 "Every JavaScript object has a prototype."

3 "The prototype is also an object."

4 "All JavaScript objects inherit their properties and methods from their prototype."

In other words, back to the most simplistic way to answer this: In javascript, a Function has a method called call.

As for understanding what bind does, the that = this vs .bind example in this article helps make sense of what is going on.

If that was confusing, then make sure you understand context and scope

like image 36
CaffeinateOften Avatar answered Jan 06 '23 14:01

CaffeinateOften