Reputation: 6761
I need to setup shorthands for several DOM accessor methods, namely - getElementsByClassName
(qCls
), getElementById
(qId
), querySelector
(q
), querySelectorAll
(Q
) - such that they are available:
q(selector)
as a shorthand for document.querySelector(selector)
throughout my code (in any scope or context).paragraph.q(selector)
as a shorthand for paragraph.querySelector(selector)
.I know the manual way to do this is:
window.Q = function(sel){
console.dir(document.querySelectorAll(sel));
};
Node.prototype.Q = function(sel){
console.dir(this.querySelectorAll(sel));
};
// TEST
var p = document.querySelector("p");
Q("a"); // should have two elements
p.Q("a"); // should have one element
<a>1</a>
<p><a>2</a></p>
But this has duplicacy - repeating exactly the same function again with only a minor difference (document
vs this
) - so I intend to eliminate that duplicacy.1
Now, what I think would work to achieve this is a pattern like:
window.Q = helperFunc(someFlag);
Node.prototype.Q = helperFunc(someOtherFlag);
where the helperFunc
handles the logic for the return value, based on the flags. Based on this, I wrote the following:
function outputQFunc(context) {
return function(selector) {
console.dir(context.querySelectorAll("a"));
};
}
window.Q = outputQFunc(document);
Node.prototype.Q = outputQFunc(this);
However, this has the obvious downside that the this
context for Node.prototype.Q
permanently points to the global scope, instead of the node which called this function. I could instead eliminate the context
:
function outputQFunc() {
return function(selector) {
console.dir(this.querySelectorAll("a"));
};
}
but then the this
does not point to the document
in case of the window.Q
.
So, my question is, how to achieve this?
Notes:
filter
s and stuff to the result of doc.qsAll
before return
ing it. In such cases, the duplicacy magnifies.Once my query got resolved, if anyone is interested in the final code I reached, this is it, which I personally find very DRY and extensible:
var DOM_HELPERS = {
/**
* short hand for document.querySelector
* @param {string} selector selector to match element
*/
q: function(selector) {
return this.querySelector(selector);
},
/**
* short hand for document.querySelectorAll
* @param {string} selector selector to match elements
*/
Q: function(selector) {
return this.querySelectorAll(selector);
},
/**
* short hand for document.getElementById
* @param {string} id selector to match element
*/
qId: function(id) {
return this.getElementById(id);
},
/**
* short hand for document.getElementsByClassName
* @param {string} cls selector to match elements
*/
qCls: function(cls) {
return this.getElementsByClassName(cls);
}
};
for (var i = 0, funcs = Object.keys(DOM_HELPERS), len = funcs.length, funcName, func; i < len; i++) {
funcName = funcs[i];
func = DOM_HELPERS[funcName];
window[funcName] = func.bind(document);
Node.prototype[funcName] = func;
}
Upvotes: 0
Views: 25
Reputation: 370979
Use bind
on your helper function to specify a custom this
context for window.Q
(and use the default this
otherwise, which will point to the proper calling context when called on a node):
function qSA(sel) {
console.dir(this.querySelectorAll(sel));
}
window.Q = qSA.bind(document);
Node.prototype.Q = qSA;
// TEST
var p = document.querySelector("p");
Q("a"); // should have two elements
p.Q("a"); // should have one element
<a>1</a>
<p><a>2</a></p>
Upvotes: 1