qarthandso qarthandso - 6 months ago 19
Javascript Question

Trying to Implement Python-Style len() in JavaScript

I've been reading a lot about

call()
and
bind()
in JavaScript, specifically the Creating Shorcuts section on this MDN article.

I'm trying to implement the following Python-esque function in JS:

var arr = [1,2,3];
len(arr); // 3


I do realize this is a contrived example, but I'm trying to wrap my head around these methods. Here's how I implemented it:

var len = Function.prototype.call.bind( Array.prototype.slice.length );
len([1,2,3]);


When I run it, I get:

len([1,2,344])
^

TypeError: len is not a function
at Object.<anonymous> (/private/var/folders/j6/3fs5_k3n17z_0j2xrwj6sphw0000gn/T/CodeRunner/Untitled 11.js:2:1)
at Module._compile (module.js:435:26)
at Object.Module._extensions..js (module.js:442:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:311:12)
at Function.Module.runMain (module.js:467:10)
at startup (node.js:136:18)
at node.js:963:3


What am I missing here to understand how this works?

Answer

When you're setting the variable len, in your code, you're actually setting len to a copy of the function Function.prototype.call, with a this (context) of Array.prototype.slice.length.

I think you're misunderstanding the use of bind(). Say I have a function len:

var len = function() {
    return this.length;
};

And you wanted to get the length of an array:

len.call([1,2,3]);

In this case, this in len is the array [1,2,3], because we used call to supply this. Say we want to permanently bind that array to that function and store it in a variable we can use anytime:

var myArrayLen = len.bind([1,2,3]);

Now, myArrayLen is basically a copy of len, permanently bound with a this of [1,2,3]. If we call it, it returns 3.

In your example, Array.prototype.slice.length is actually the length of the function Array.prototype.slice, which corresponds to the number of arguments that can be passed to the function.

There is no built in length() function, so to follow your (admittedly) contrived example, we just need to make a function that provides the length, add it to the array prototype, and bind it using Function.prototype.apply.bind();:

Array.prototype.len = function () { return this.length; };
var len = Function.prototype.apply.bind(Array.prototype.len);
len([1,2,3]); // 3