Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method Set.prototype.has called on incompatible receiver undefined

Tags:

javascript

After years of using JavaScript I met an error that I had never seen.

I wanted to calculate the intersection between two Sets, so I wrote:

let a = new Set([1, 2, 3]);
let b = new Set([2, 3, 4]);

let intersection = [...a].filter(x => b.has(x));

console.log(intersection);

And it works, but I noticed that I can shorten the above code. Since the filter method just wants a function and invokes it no matter how it is defined, and I wrote:

let a = new Set([1, 2, 3]);
let b = new Set([2, 3, 4]);

let intersection = [...a].filter(b.has);

console.log(intersection);

And in this case, unexpectedly, I receive the following error:

Uncaught TypeError: Method Set.prototype.has called on incompatible receiver undefined

I also noticed that this doesn't happen if I bind Set.prototype.add to the variable:

let a = new Set([1, 2, 3]);
let b = new Set([2, 3, 4]);

let intersection = [...a].filter(Set.prototype.bind(b));

console.log(intersection);

My question is: why does it happen? Why b.has is not a valid callback?

like image 568
Cristian Traìna Avatar asked Aug 14 '18 21:08

Cristian Traìna


2 Answers

has method loses internal this context when you pass it as a callback.

That is the reason it works when you use bind to provide it right context.

For more info it has been documented here

like image 113
Sushanth -- Avatar answered Nov 10 '22 06:11

Sushanth --


You can use the Array#filter function and pass thisArg as the second parameter. So the has will take this second parameter as it's this, and proceeds to evaluate or compare.

Here's an example:

function compare(a, b) {
    return [...a].filter(Set.prototype.has, b);
}

let a = new Set([1, 2, 3]);
let b = new Set([2, 3, 4]);

console.log(compare(a, b));

Another idea:

function compare(a, b) {
    return new Set([...a].filter(Set.prototype.has, b));
}

let a = new Set([1, 2, 3]);
let b = new Set([2, 3, 4]);

console.log([...compare(a, b).values()]);
like image 32
robe007 Avatar answered Nov 10 '22 06:11

robe007