The Short-Hand Function Technique
A Quick Way to Minify Methods in JavaScript
As a programmer I’m often toying with different ways of doing things and quite a few at one time( too many? probably ) — but when it comes to programming my mind is constantly brimming with ideas.
I was experimenting with adding short-hand to the document object based on the camel case naming convention. “Whoa whoa whoa,” you protest, “what’s that mean, man?”
Basically I wanted to turn document.querySelector
and document.addEventListener
into document.qS
and document.aEL
respectively. why? I’m profoundly lazy and curious. It’s true that this isn’t a real big achievement. It can be done as simply as:
document.qS = document.querySelector;
document.aEL = document.addEventListener;
but I wanted to adjust the object in such a way that all camel cased methods became adapted to a short-hand method. Frankly, I was just tired of writing out these long chained methods and wondered if I could make it easier. Not for production, of course, but to sate my own silly desire and to use to mock-up some play code occasionally.
The following is a demo of what I came up with and an explanation:
let b, d, e;
for(let k in(d=document)) d[k[0]+k.split("").filter(_=>_<{}).join("")] = d[k];e=_=>d.qS(_);
b=_=>d.aEL.bind(_);
What’s happening here?
- I’m declaring
d
asdocument
- Iterating through each of the keys in
document
- Determining the camel case letters of a key (
k[0]
is the first letter which is lowercase and then I use thefilter
method on the rest of the key to find any uppercase letters) - We then apply the first lowercase letter and any uppercase letters found as a new method on
document
that references the original method - ergodocument.querySelector
becomesdocument.qS
Point of Note: The above uses a trick of comparing a character to an object to determine its case. If true the case is upper, and if false the case is lower. Examples:
"c"<{}; //false
"C"<{}; //true"E"<{}; //true
"e"<{}; //false
What’s happening here may seem odd so I’ll explain it:
- an object is converted to a string when it is compared.
{}
in the above example is turned into"[object Object]”
- In ASCII/UTF-16 uppercase
A-Z
have character code values from 65–90 and lowercasea-z
have character code values from 97–122. [
is character code 91 which is between both character sets. This means that when"A"<{}
it is comparing"A"
or character code 65 with"["
or character code 91.- Since 65 is less than 91
"c"<{}
is true which we can interpret as the character being uppercase. - If it were
"a"<{}
we would be comparing character code 97(a
) with character code 91([
) - Since 97 is not less than 91
"a"<{}
is false which we can interpret as the character being lowercase. - It’s important to realize that
{}
doesn’t have to be an empty object — it can be any object since all objects convert to"[object Object]"
when turned into a string.
Short Hand in Custom Objects
The shortening of the methods on the document
object is certainly interesting but it wasn’t foolproof by any stretch of the imagination. Sure, document.qS
and document.aEL
came out working, but what if I had two methods that utilized the same camel case characters? The document
object wasn’t built with my crazy short-hand nonsense in mind so it was completely unreliable when it came to what methods I would be adjusting.
but what about my own, custom objects? “Let me try that!”, I shout from my home desk at 3am, haphazardly falling out of my chair and spilling tea all over my Walking Dead pajamas because I’m just that excited.
Further Code Explanation
The following code is nothing special. It is a copy of the above code in a functional format, with an error that will occur if I run into a duplicate of the same key. For instance, if I had addEventListener
(aEL) and abstractEventLoop
(aEL) on the passed object it would throw an error because I don’t want two keys to have the same short-hand name and overwrite each other. You may think that this is fine as long as the one key you’d like as short-hand comes after the other, but this is impossible to guarantee. Object keys are not returned in any finite order so we can’t rely on that. Anyway, here’s the function ( ObjectCheck
)
// the short-hand technique
function ObjectCheck(myObject) {
let obj = Object.assign(myObject, {});
for (let key in obj) {
if (!(/^([a-z])([A-Z])+$/).test(key)) {
let formatted = key[0] + key.split("").filter(_ => _ < obj).join("");
if (formatted in obj) throw Error("Key already Exists. Object is not short-hand capable");
else obj[formatted] = obj[key];
}
}
return obj;
}
Just to explain once more because by golly(who says by golly anymore?) that doesn’t look the easiest to comprehend. I aim my blog towards anyone tired of jargon and gibberish after all. *cracks knuckles* OKAY, so:
function ObjectCheck(myObject) {}
we receive an object
when this function is called. Since we’re a big fan of functional programming
(Understanding Functional Programming — Zak Frisch) we know that we don’t want to change the object
we passed in, what we want to do is create a copy and adjust the copy. To do this we use Object.assign
(MDN) which will allow us to duplicate the object. Object.assign
will return a copy but it always takes at least two parameters. Our second parameter will be an empty object.
function ObjectCheck(myObject) {
//duplicate the passed in object(myObject) in obj
let obj = Object.assign(myObject, {});
}
As in the above code we then need to iterate over the objects keys.
for (let key in obj) {
if (!(/^([a-z])([A-Z])+$/).test(key)) {
let formatted = key[0] +
key.split("")
.filter(_ => _ < obj)
.join("");
if (formatted in obj) throw Error("Key already Exists. Object is not short-hand capable");
else obj[formatted] = obj[key];
}
}
return obj;
We use the for...in
loop to iterate. There is a Regular Expression that is used to test if a function is camel case before we try adding a shorthand key. We do this because otherwise if we have a method like append
it would simply be short-handed to a
and we don’t want that.
Afterwards we ask if the camel case key which is stored in the formatted
variable (aEL in the case of addEventListener
) is already within obj
— remember, we want to prevent any overwriting of keys, so we throw an error that says as much. If formatted
is not within obj
we assign the original function to our short-hand function. A.e. document["aEL"] = document["addEventListener"]
Still confusing? That’s fine! Let’s try it out!
Custom Object Example
In the above section we created our ObjectCheck
function which will check if our object is short-hand capable and convert it! We still need an object to convert. Let’s create a simple one:
{
sayHello() {
document.body.innerText += " hello!"
return this;
},
sayGoodbye() {
document.body.innerText += " goodbye!";
return this;
}
}
The above code is an object with two methods: sayHello
and sayGoodbye
— they will add hello
to the screen or goodbye
to the screen respectively.
Simple right? If you don’t understand return this
— what that is doing is, instead of stopping after adding the text to the screen, it returns the object back after using its method. This allows you to call other methods immediately ( what we call chaining methods)and it looks like this: obj.sayHello().sayGoodbye().sayGoodbye().sayHello();
which we can use instead of writing:
obj.sayHello();
obj.sayGoodbye();
obj.sayGoodbye();
obj.sayHello();
It’s a pretty common technique used by most JavaScript libraries — most notably JQuery. Anyway…
We’re going to pass this object to our short-hand converter and use it. What we should see from the returned object is that we have the ability to use sayHello
as sH
and sayGoodbye
as sG
— let’s try it!
As you can see our ObjectCheck
function worked beautifully.
let myobj = ObjectCheck({
sayHello() {
document.body.innerText += " hello!"
return this;
},
sayGoodbye() {
document.body.innerText += " goodbye!";
return this;
}
});myobj.sH().sG().sH().sG();
We can now use this to short-hand any objects that we want to use and get sick of writing out full method names for. Now, depending on your disposition, you may say “Wait a minute, Zak. That adds twice as many keys on the same object!” or “Zak, that’s great, I can now switch back and forth between the two keys if I’m feeling lazy or want to be clear!” — really it’s all down to how you view it.
One last thing in the interest of clarity. It’s important to realize that because our short-hand functions are direct references to the full named functions, any change to the full named functions will affect how the short-hand function evaluates. The short-hand function is not a copy, it is a reference. This works out fine for me, but it may surprise some people if you’re not aware of it. Secondly, this leads to a trick. If you ever find yourself coding in short-hand and forgetting what it is that your short-hand function references you can simply use obj.fn.name
to retrieve the full length name.
Conclusion
I enjoyed implementing this technique and it helped me kick off dust on a few of my stagnant brain-cells. I’ve decided to use it in several small projects in solidarity for that part of me that always loves to write shorter code.
Typically in my conclusion sections I have some follow-up information, and more in-depth explanation of concepts, but this time I think I’ll avoid all that as the bulk of information is provided in the article itself. I just wanted to share an interesting idea that I had and the thought process that allowed me to flesh it out! Maybe someone will find it useful or expand on the idea!
Thanks for reading!