1

I'm playing around with a micro library for use within projects and I'm having difficulty adding a method to a function.

In this case I have shorthanded document.querySelector() which is all good and works as needed. However I have no real idea how to add a method to that which inherits the element from the selector function.

This is similar to how jquery works but a lot of code examples online are a fair few years old. I'm wanting a modern solution and to understand how this works going forward. I really hope someone can educate me and help to get this to work.

Cheers!

let S = (selector, container = document) => {
    return container.querySelector(selector);
};

S.prototype = {
  classAdd: (_class) => this.classList.add(_class) 
};

S('div').classAdd('red');

https://codepen.io/matt3224/pen/NMqBLp?editors=0010

mattpilott
  • 356
  • 1
  • 6
  • 13

3 Answers3

3

Arrow functions don't have a prototype property. To get it working use a normal function, that's not not modern. Arrow functions are not a replacement, but an addition. You could also use a class though - maybe that's what you mean with modern.

class S {
  constructor(selector, container = document) {
    this.selected = container.querySelector(selector);
  }

  classAdd(clazz) {
    this.selected.classList.add(clazz);
  }
}

new S('#foo').classAdd('bar');
console.log('#foo has bar as class: ', document.getElementById('foo').classList.contains('bar'));
<div id="foo">
  foo
</div>
baao
  • 71,625
  • 17
  • 143
  • 203
  • I did try a normal function but that also did not work, https://codepen.io/matt3224/pen/NMqBLp?editors=0010 – mattpilott Apr 20 '18 at 23:28
  • using the class syntax is nice however i would prefer a functional approach – mattpilott Apr 20 '18 at 23:29
  • Well, like I wrote, use a normal function then... @matt3224 – baao Apr 20 '18 at 23:31
  • Thanks @baao but I can't get that to work, see this updated pen https://codepen.io/matt3224/pen/vjOvoe?editors=0010 – mattpilott Apr 20 '18 at 23:55
  • Okay now i have something that works using revealing module but is there anyway i can just get the element if i console.log `S('div')`? https://codepen.io/matt3224/pen/jxPdqo?editors=0010 – mattpilott Apr 21 '18 at 00:21
1

Let's take a closer look at your code, shall we?

First block:

let S = (selector, container = document) => {
  return container.querySelector(selector);
};

This code declares a simple function and assigns function reference to variable S
The function itself returns HTML element as per querySelector documentation, which can not be use in a chain notation:

S('div').something();  // won't work
let ele = S('div');    // works 


Second block:

S.prototype = {
  classAdd: (_class) => this.classList.add(_class) 
};

Because S is a simple function (NOT a Function-Object) it has no prototype element as a regular Object does. However, the code still works as it creates a new property named propotype on the S function.

To prove what has been stated above, I have created following code example:

let S = (selector, container = document) => {
  return container.querySelector(selector);
};

let ele = S('div');
console.log(ele);

S.prototype = {
  classAdd: (_ele, _class) => _ele.classList.add(_class)
};

S.prototype.classAdd(ele, 'red');
.red {
  padding: 10rem;
  background-color: coral;
}
<div>Text inside div</div>

If you want to use chain notation such as S('div').classAdd(..) your first block function must return a valid object to act upon

let S = (selector, container = document) => {
  return {
    ele : container.querySelector(selector),
    classAdd: function(_class) { // regular function notation as it needs this 
      this.ele.classList.add(_class) 
    }
  };
};

S('div').classAdd('red')
.red {
  padding: 10rem;
  background-color: coral;
}
<div>Inside Div</div>
MaxZoom
  • 7,619
  • 5
  • 28
  • 44
  • Good breakdown, I managed to progress and only have 2 issues left to solve before i can get this working and gain the understanding https://codepen.io/matt3224/pen/jxPdqo?editors=0010 – mattpilott Apr 23 '18 at 17:57
  • My issues are that logging `S('div')` return the object which i would expect however i ideally want the element itself. – mattpilott Apr 23 '18 at 17:58
  • To achieve `S(selector)[0]` how can i do that when i'm returning an object? – mattpilott Apr 23 '18 at 19:33
  • As you use `querySelector` there is only one matching element (or none at all). So to get it, use `S.ele` – MaxZoom Apr 23 '18 at 20:07
0

you can define classAdd in the S and return an object containing the methods :

let S = (selector, container = document) => {
  let element = container.querySelector(selector);

  return {
    classAdd: (_class) => {      
      element.classList.add(_class)
    }
  }
};

S('div').classAdd('hello')
<div>
  hello
</div>
Taki
  • 17,320
  • 4
  • 26
  • 47