l33t Speak translator
To start with, I'd like to give you credit for using "use strict" and limiting the scope of variables using functions.

Your tol33t() function is weird to me.  If the randomcase button is checked, you call randomizeCase() with no arguments.  What are you randomizing the case of?  It turns out that randomizeCase() calls changeWords(), so it turns out that the two code branches have something in common after all.  That wasn't apparent from looking at tol33t().

There should be clearer separation responsibility between the DOM-interaction and text-translation layers of code.  The text translation code should reside in pure functions (whose results depend solely on their parameters) that you could call from the JavaScript console or from a unit testing engine.  That separation of concerns could be accomplished with:

function onTranslateButtonClicked() {
    var l33tText = toL33t(elite.value, adv.checked);
    if (randomcase.checked) l33tText = randomizeCase(l33tText);
    leet.value = l33tText;
}


Your "l33t the words object" initialization routine lays a trap for anyone trying to  read the code.  When code in changeWords() refers to the words associative array, one would reasonably think that it's using the definition above (i.e., words = { "am": "m", … }) instead of the munged version (words = { "4m": "m" }).  Better to make that munging explicit when you define words (and do so by returning a copy rather than mutating the dictionary as you iterate):

var words = l33tKeys({
    "am": "m",
    …
});

function l33tKeys(dict) {
    var l33tDict = {};
    for (var word in dict) {
        l33tDict[changeWord(word)] = dict[word];
    }
    return l33tDict;
}


I would write changeLetters() as:

 // letterSubsts may be alphabet or alphabet2
function changeLetters(text, letterSubsts) {
    return text.toLowerCase().replace(/[a-z]/g, function(letter) {
        return letterSubsts[letter] || letter;
    });
}


… which is actually analogous to your implementation of changeWords().