Error when assigning native function context

Asked

Viewed 61 times

2

When using the code:

let _  = document.querySelector.bind(document);
let __ = document.querySelectorAll.bind(document);

I inform the context where querySelector and querySelectorAll will be called.

But when I call them sequentially, for example:

let steps = _(".wizard-steps").__("li.nav-item");

I get the error:

_(...).__ is not a Function

When I call it that way it works:

let steps = _(".wizard-steps").querySelectorAll("li.nav-item");

I tried to:

let _  = document.querySelector.bind(document);
let __ = _.bind(_);

But to no avail.

2 answers

3

document.querySelector.bind() returns a HTMLElement in accordance with documentation.

There are at least two methods querySelectorAll() available, what manipulates a document and what manipulates an element.

When You Apply O _ (I hate those names that are expendable) it returns an element and therefore the querySelectorAll() to be called is that of Element since she is the mother of HTMLElement.

When you use the __ is using the document method on top of an object that is an element (recalls the return of _?). Doesn’t work.

I haven’t done tests of what could work, but the explanation why it doesn’t work is there. I think you have to call the HTMLElement or Element directly and not the document.

3


First we have to understand what bind makes. According to documentation:

creates a new Function that, when called, has its this keyword set to the provided value

That is, the bind creates a new function which, when called, has the this set to the value you were informed. So when you do:

let _ = document.querySelector.bind(document);
let __ = document.querySelectorAll.bind(document);

Are you saying that _ will always call document.querySelector, and __ will always call document.querySelectorAll.

That’s why _('alguma coisa') works because it’s like you call document.querySelector('alguma coisa'). But the return of this function is a HTMLElement, who does not have the method __ (remember that __ was defined as a function calling document.querySelectorAll).

A solution to do what you want would be to define __ in the prototype of HTMLElement, making it point to the desired method (in case, querySelectorAll):

let _  = document.querySelector.bind(document);
HTMLElement.prototype.__ = HTMLElement.prototype.querySelectorAll;

_('#abc').__('span').forEach(s => console.log(s.innerText));
<p id="abc">
  Lorem <span>ipsum</span> dolor <span>sit</span> amet.
</p>

Thus, _ keeps calling document.querySelector, but __ calls the querySelectorAll of HTMLElement returned by _.


Of course you can keep both options (both on document how much in the prototype):

let _  = document.querySelector.bind(document);
let __  = document.querySelectorAll.bind(document);
HTMLElement.prototype._ = HTMLElement.prototype.querySelector;
HTMLElement.prototype.__ = HTMLElement.prototype.querySelectorAll;

__('span').forEach(s => console.log(s._('a').innerText));

_('#abc').__('span').forEach(s => console.log(s.innerText));
<p id="abc">
  Lorem <span>ipsum <a href="">link1</a></span> dolor <span>sit <a href="">link2</a></span> amet.
</p>

So when _ or __ are called directly, will be calling the methods of document, and when they are called in the result of these, they will be calling the methods of the respective HTMLElement's.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.