You're almost there - the issue is that the standalone expression
$('#list')
will have the default calling context of window
(the this
value inside the $
function). If you want to create an instance which can use prototype methods, put new
before the call to $
:
const $ = function(a, b) {
this.$el = document.querySelector(a);
}
Object.assign($.prototype, {
hasClass: function(selector) {
return this.$el.classList.contains(selector);
}
})
console.log(new $('#list').hasClass('list'));
console.log(new $('#list2').hasClass('foo'));
<div id="list"></div>
<div id="list2" class="foo"></div>
If you don't want to put new
before every call, you can use Object.create
inside $
:
const $ = function(a, b) {
const $obj = Object.create(proto);
$obj.$el = document.querySelector(a);
return $obj;
}
const proto = {
hasClass: function(selector) {
return this.$el.classList.contains(selector);
}
};
console.log($('#list').hasClass('list'));
console.log($('#list2').hasClass('foo'));
<div id="list"></div>
<div id="list2" class="foo"></div>
I think the way jQuery does it is, the returned object's internal prototype is $.fn
, eg:
const $ = function(a, b) {
const $obj = Object.create($.fn);
$obj.$el = document.querySelector(a);
return $obj;
};
$.fn = {
hasClass: function(selector) {
return this.$el.classList.contains(selector);
}
};
console.log($('#list').hasClass('list'));
console.log($('#list2').hasClass('foo'));
<div id="list"></div>
<div id="list2" class="foo"></div>