0

I want to implement something to make myself instead of writing something.querySelector() to write $, I've fixed the half of the problem which is when I want to make document.querySelector() instead, I can now use $

<div>
<button>hi</button>
</div>
    let $ = (x) => {
        return document.querySelector(x);
    }
div = $("div");

But the thing that I want to do now is to select the button from inside the div, so now I can't do:

div.$("button");

I want to do it, I know a little bit about prototypes, but I don't know how to implement this thing, How?

[EDIT]: I've seen many people saying that It's a bad implementation, could you please tell why?

Mathew
  • 129
  • 9
  • try using children like `div.children()` – Ankit Jindal Aug 25 '20 at 19:57
  • If you want to use it like that, you would probably have to attach `$` to the `Element.prototype` – Taplar Aug 25 '20 at 19:57
  • @Taplar, good answer, I was reading about that on MDN a few seconds ago, when I do that, do I need to keep the function I've written? in other words, will this solution replace the need for the function I've written (for the " document. " ) – Mathew Aug 25 '20 at 20:02

5 Answers5

1

If you don't want to mess with prototypes, you can have $ accept a second argument, the parent to select from.

const $ = (x, parent = document) => {
  return parent.querySelector(x);
}
const div = $("div");
const button = $('button', div);
console.log(button);
<div>
  <button>hi</button>
</div>

Changing prototypes is bad practice, but it's doable:

const $ = (x, parent = document) => {
  return parent.querySelector(x);
}
Element.prototype.$ = function(selector) {
  return $(selector, this);
}
const div = $("div");
const button = div.$('button');
console.log(button);
<div>
  <button>hi</button>
</div>
Snow
  • 3,820
  • 3
  • 13
  • 39
  • This is a very good idea, but Huh, I want to miss with prototypes, I love the hard things – Mathew Aug 25 '20 at 19:59
  • Could you please tell why it's a bad idea to implement that? – Mathew Aug 25 '20 at 20:10
  • https://stackoverflow.com/questions/6223449/why-is-it-frowned-upon-to-modify-javascript-objects-prototypes offers a few explanations – Snow Aug 25 '20 at 20:11
1

window.$ = HTMLElement.prototype.$ = function(selector) {
  if (this === window) {
    return document.querySelector(selector);
  } else {
    return this.querySelector(selector);
  }
};

console.log($('div').$('button'));
<div>
<button>hi</button>
</div>

You can, I don't know if I would, put the method on the window and HTMLElement prototype to allow chaining like you asked about.

Taplar
  • 24,788
  • 4
  • 22
  • 35
  • Don't think adding the function to `window` object is necessary. You could define the function separately and then add it to `HTMLElement` prototype --> `HTMLElement.prototype.$ = $;`. This way you can call it as function or as a method on an html element. – Yousaf Aug 25 '20 at 20:17
  • 2
    I just chained it like this, because `var $ = method` in the global scope is essentially just attaching it to the window anyway. @Yousaf And if you look at the snippet, I *am* calling it as a function and a method, :) – Taplar Aug 25 '20 at 20:18
  • 1
    Personally I would argue that this whole approach is problematic. For those familiar with jQuery, the gut reaction to seeing `$` being used is to expect that it is jQuery. Using it like this is bound to lead to confusion. – Taplar Aug 25 '20 at 20:21
0

It's not recommended, but you can modify Element.prototype and Document.prototype.

Element.prototype.$ = Document.prototype.$ = function(x){
    return this.querySelector(x);
}
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
0

Probably not the best approach but you could assign a property $ to the element that is a function that queries that element

let $ = (x) => {
  let el = document.querySelector(x)
  el.$ = (y) => el.querySelector(y)
  return el;
}
div = $("div");

console.log(div.$('button'))
<div>
  <button>hi</button>
</div>
charlietfl
  • 170,828
  • 13
  • 121
  • 150
0

It's very simple and you need only two lines of code to make it all work as expected.

Document.prototype.$ = Document.prototype.querySelector
Element.prototype.$ = Element.prototype.querySelector
Arthur Grigoryan
  • 358
  • 3
  • 12