Back to Home

Create jQuery Library with Vanilla JS

July 28, 2015

It's kind of fun project. Create jQuery Library like functions with vanilla JS.

$ object

What is $? $ is not a special keyword. It is just a variable name. It will return every incidet of argument from DOM. The task is to create an array like element (must have a function of length) when it is called $(); so we can manuplate the DOM.

var $ = function(selector) { if (!(this instanceof $)) { return new $(selector) //this way we don't have to use 'new' every time } var elements = document.querySelectorAll(selector); for (var i=0; i"<"elements.length; i++) { this[i] = elements[i]; } this.length = elements.length; } //or simply: Array.prototype.push.apply(this, elements);

Most important concept here is that 'this'. The reason we are creating $ is that we want to return every elements that are instance of $. Without it, we can't call $('selector').OTHERFUNCTION.

$.expend(target, object)

Don't think too hard. You will ruin it. This was one of the function that I was most struggle with. How to make sure that the function is assigned as same as other function? Just assign it.

$.expend = function(target, object) { for (var i in object) { target[i] = object[i]; }; return target; };

$.isArray(obj)

This will return true if the object is Array (not Arraylike obj)

$.isArray = function(obj) { Object.prototype.toString.call(obj) === "[object Array]" };

This is something to remember. To see if the argument is true array, the only way to check is to see toString.call(obj) and return '[object Array]'

$.ArrayLike(obj)

Like what $(); returns, arraylike stuff but not exactly an array. So what's difference between array and array-like obj? An array-like object has:

  • indexed access to elements and the property length that tells us how many elements the object has.
  • It does not however have: array methods such as push, forEach and indexOf.
  • $.ArrayLike = function(obj) { if (!(obj.push || obj.forEach || obj.indexOf)) { return true; } return false; };

    $.each

    As you guess, each function is one of the fundamentals. One thing about this challenge is that the cb looks like function(index, value) {};

    $.each = function(collection, cb) { if ($.isArray(collection)) { for (var i=0; i'<'collection.length; i++) { return cb.call(collection[i], i, collection[i]); } else if ($.isArrayLike(collection)) { for (var prep in collection) { return cb.call(collection[prep], i, collection[prep]); } } }; return collection; };

    $.makeArray

    This function returns new array. To do so we can use $.each()

    $.makeArray = function(arr) { if ($.isArray(arr)) { return arr; } var newarr = []; $.each(arr, function(i, item) { newarr[i] = item; }); }

    $.proxy

    Take a function and retuns a new one that calls the original with a particular context.

    $.proxy = function(fn, context) { return function() { return fn.apply(context, arguments) }; };

    The key here is to invoke the function with apply, we need another function. The proxy returns a function which will call the function. The reson is that if the function being called then it will set 'this' something other than context.

    $.html(mewHTML)

    There is a property called 'innerText' which returns text within the element

    $.html = function(newHtml) { if (arguments.length) { return $.each(this, function(i, element){ element.innerText = newHTML; }) }else { return this[0].innertext; } }

    $.text(newText)

    The text function will get/set the text portion of an element. This is actually big hard question. Let's take a look more on textnode.

    textnode is literally 'text' in the element. It is possible to create text node like var text = document.createTextNode('hello');. More importantly, each node like elementnode and textnode has different value.

    The challenge of this problem is if argument is not passed, first, we have to get all textnode from each and every nested elements. If the element's child nodetype === 3, which is TEXT_NODE, then it will return, otherwise go down to child's child node until it finds text node to return

    $.getText = function(node) { var text = ''; $.each(node, function(index, child){ if (node.nodetype === 3) { text+=child.nodeValue; }else { text+= getText(child.childNodes); } }); return text; }; $.text = function(newText) { if (arguments.length) { //this.html(""); this will do el.innerHTML = "" $.each(this, function(index, element) { element.innerHTML = ""; var textnode = document.createTextNode(newText); element.appendChild(textnode); }) } else { return getText.call(this[0].childNodes) } };