Last active
August 29, 2015 14:27
-
-
Save jhartman86/1aee90a4635638ae8154 to your computer and use it in GitHub Desktop.
Solutions for js skill set evaluation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Consider this function the place where you go through and customize things | |
* after an external script has created some defaults, but you need to customize | |
* things. Everything has to occur w/in this function. If there are things you | |
* would change entirely to make it more understandable, do so. Also, assume you | |
* can use the latest ECMA script standards (no shitty IE8 support, or 9 for | |
* that matter). | |
*/ | |
runtime.initialize(function( $, markupData ){ | |
/** | |
* Disable animation on the accordion (it slides up and down by default; it | |
* should immediately snap open). Easiest route being to select the DOM element | |
* and use jQueryUI's API to just disable it. Put a comment for future people | |
* who maintain this code as to why it might be confusing. | |
*/ | |
// --- code here --- | |
/** SOLUTION *************************************************************** | |
* Its confusing b/c there are two jQuery's included; but only one (and not | |
* the one passed as the $ var into this function) has the jQuery UI accordion | |
* bound to its .data() method, where we can properly access and turn off the | |
* animate setting via jQueryUI's API. | |
**************************************************************************/ | |
jQuery('aside').accordion("option","animate", false); | |
/** | |
* Callback hell; we run into this all_the_time. Try giving this a refactor; | |
* with the goal being to a) remove nesting of callbacks, and b) that when | |
* you console log _value, it should have {valIs:12}. Key thing is that it | |
* has to return a _consistent_ result; as you never know the timing in which | |
* method1,2,3 will execute unless they're nested like this. | |
*/ | |
var input = 4; | |
this.method1(input, function( _input ){ | |
this.method2(_input, function( _input2 ){ | |
this.method3(_input2, function( _input3 ){ | |
console.log(_input3); | |
}); | |
}); | |
}); | |
/** SOLUTION *************************************************************** | |
* All the methods that need to run in order accept args: func(val, callback); | |
* this lets us use a fairly simple function to build a kind of promise | |
* factory that we can *chain*. It might not be the most readable/elegant | |
* function, but it does make the end result very readable, and it scales | |
* so we can add as many more things in order as we want vs ever-deeper | |
* nested callbacks. NOTE: this is *definitely* not the only way to do | |
* this. Important thing is we want to see if candidate can find a way to | |
* flatten out nested callbacks. | |
**************************************************************************/ | |
function inOrder(callable){ | |
return function(_value){ | |
var df = $.Deferred(); | |
callable(_value, function( newVal ){ | |
df.resolve(newVal); | |
}); | |
return df.promise(); | |
}; | |
} | |
var input = 4; | |
inOrder(this.method1)(input). | |
then(inOrder(this.method2)). | |
then(inOrder(this.method3)). | |
done(function(result){ | |
console.log('result: ', result); | |
}); | |
/** | |
* The variable `markupData` contains a large array of objects (9999 to be | |
* specific) like so: | |
* [{classes: 'alpha beta gamma', content: 'lorem ipsum ...'}, ..., ...] | |
* ------------------------------------------------------------------------- | |
* Task is to loop through all the objects in the array and generate DOM | |
* markup inside the <main> element, *after* the <h4></h4> tag, like: | |
* <div class="alpha beta gamma" data-index="{index}"> | |
* <span>lorem ipsum</span> | |
* </div> | |
* WITHOUT using jQuery. {index} is the 0-based index of the item you're | |
* looping through. | |
* ------------------------------------------------------------------------- | |
* IMPORTANT: performance matters. Beyond just not using jQuery, the real | |
* criteria for this is doing it in the fastest/most-performant way possible. | |
* Obviously 9999 is a somewhat arbitrarily large number; the key is | |
* generating code that runs FAST in the browser. So - write the solution | |
* wrapped inside the trackTime method, which will use chrome devtools' | |
* console.time() method to do a rough benchmark of its performance (you'll | |
* see the time logged to the console). I believe Firefox supports | |
* console.time() as well, but not sure, so best bet is to use Chrome for | |
* working on this. | |
*/ | |
this.trackTime(function(){ | |
// --- code here --- | |
}); | |
/** SOLUTION *************************************************************** | |
* Criteria we're looking at: | |
* 1) Since we specified performance-critical, is documentFragment being | |
* used to minimize the number of repaints the browser has to do? | |
* 2) For generating the <span> tag - is it being done w/ innerHTML and then | |
* parsing a string that contains the <span> tags inside (which is slower), | |
* or is the node being generated with createElement (which is faster). | |
* NOTE: this is kind of subjective, as using innerHTML increases readability | |
* and really shouldn't be considered bad practice (we do it all the time), | |
* but for manipulating a few thousand nodes, its significantly slower. | |
* 3) If they're NOT using documentFragment, are they appending the nodes to | |
* <main> tag on every iteration of the loop (major no-no), or is there | |
* some other clever way of getting around that? | |
**************************************************************************/ | |
this.trackTime(function(){ | |
var frag = document.createDocumentFragment(); | |
for( var key in markupData ){ | |
var div = document.createElement('div'), | |
span = document.createElement('span'); | |
div.className = markupData[key].classes; | |
div.setAttribute('data-index', key); | |
span.innerText = markupData[key].content; | |
div.appendChild(span); | |
frag.appendChild(div); | |
} | |
document.querySelector('main').appendChild(frag); | |
}); | |
/** | |
* Lastly, again w/out jQuery, bind click listeners that fire *once* | |
* and console.log() the value stored in the data-index attribute whenever one | |
* of the <div>s just created gets clicked, _but_ do not use an external | |
* variable to track the state of whether something has already been | |
* clicked or not. i.e.: no doing: | |
* var isClicked = false; | |
* ... <code> ... | |
* if(clicked === false){ | |
* <code>; | |
* isClicked = true; | |
* } | |
*/ | |
// --- code here --- | |
/** SOLUTION *************************************************************** | |
* We're looking for code that uses removeEventListener to | |
* unbind after one click. | |
**************************************************************************/ | |
var nodeList = document.querySelectorAll('main > div'), | |
nodeArray = Array.prototype.slice.call(nodeList), | |
onClick = function(){ | |
console.log(this.getAttribute('data-index')); | |
this.removeEventListener('click', onClick); | |
}; | |
for(var i = 0, l = nodeArray.length; i < l; i++){ | |
nodeArray[i].addEventListener('click', onClick); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment