If you want something that is cross browser, with pure javascript (not using a library like jQuery), then you will need something like this (which is a similar idea to @JoshCrozier answer but with a load of compatibility functions instead thrown in, which will default to the natives if they are available. Has a UMD at the bottom to allow you to use module loaders so that you can keep these in a separate file - a library). === fun what? :)
Javascript - the compatability bits
/*global window, document, module, define, $ */
(function () {
'use strict';
var commands = {},
MAX_UINT32 = 4294967295,
baseFunction = function () {
return;
},
privateUndefined = (baseFunction()),
hasOwn = commands.hasOwnProperty,
toClass = commands.toString,
trimFN = ''.trim,
baseArray = [],
slice = baseArray.slice,
forEachFN = baseArray.forEach,
filterFN = baseArray.filter,
$ = {},
makeRegex;
function isFunction(arg) {
return typeof arg === 'function';
}
function throwIfNotFunction(arg) {
if (!isFunction(arg)) {
throw new TypeError('is not a function');
}
return arg;
}
function isUndefined(arg) {
return privateUndefined === arg;
}
function isNull(arg) {
return null === arg;
}
function isUndefinedOrNull(arg) {
return isUndefined(arg) || isNull(arg);
}
function isObject(arg) {
return toClass.call(arg) === '[object Object]';
}
function isString(arg) {
return typeof arg === 'string';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isBoolean(arg) {
return typeof arg === 'boolean';
}
function handler(object, evt, func) {
var ret;
if (evt) {
ret = func.call(object, evt);
if (false === ret) {
evt.stopPropagation();
evt.preventDefault();
}
} else {
window.event.target = window.event.srcElement;
ret = func.call(object, window.event);
if (false === ret) {
window.event.returnValue = false;
window.event.cancelBubble = true;
}
}
return ret;
}
$.addEventListener = function (object, type, func) {
var uid = type + ':' + func,
euid = 'e:' + uid;
object[euid] = func;
if (isFunction(object.addEventListener)) {
object[uid] = function (evt) {
handler(object, evt, object[euid]);
};
object.addEventListener(type, object[uid], false);
} else if (isObject(object.attachEvent)) {
object[uid] = function () {
handler(object, null, object[euid]);
};
object.attachEvent('on' + type, object[uid]);
} else {
throw new Error('Handler could not be added.');
}
};
$.removeEventListener = function (object, type, func) {
var uid = type + ':' + func,
euid = 'e:' + uid;
if (isFunction(object.removeEventListener)) {
object.removeEventListener(type, object[uid], false);
} else if (isObject(object.detachEvent)) {
object.detachEvent('on' + type, object[uid]);
} else {
throw new Error('Handler could not be removed.');
}
object[euid] = null;
object[uid] = null;
delete object[euid];
delete object[uid];
};
if (isFunction(trimFN)) {
$.trim = function (text) {
return trimFN.call(text);
};
} else {
$.trim = function (text) {
return text.replace(/^\s+|\s+$/g, '');
};
}
if ('classList' in document.body) {
$.classList = {
contains: function (node, className) {
return node.classList.contains(className);
},
add: function add(node, className) {
node.classList.add(className);
},
remove: function (node, className) {
node.classList.remove(className);
},
toggle: function (node, className) {
node.classList.toggle(className);
}
};
} else {
makeRegex = function (className, flags) {
return new RegExp('(?:^|\\s)' + className + '(?!\\S)', isString(flags) ? flags : '');
};
$.classList = {
contains: function (node, className) {
return !!node.className.match(makeRegex(className));
},
add: function add(node, className) {
if (!$.classList.contains(node, className)) {
node.className = $.trim(node.className);
if (node.className) {
node.className += ' ';
}
node.className += className;
}
},
remove: function (node, className) {
if ($.classList.contains(node, className)) {
node.className = $.trim(node.className.replace(makeRegex(className, 'g'), ''));
}
},
toggle: function (node, className) {
if ($.classList.contains(node, className)) {
$.classList.remove(node, className);
} else {
$.classList.add(node, className);
}
}
};
}
function checkObjectCoercible(inputArg) {
if (isUndefinedOrNull(inputArg)) {
throw new TypeError('Cannot convert "' + inputArg + '" to object');
}
return inputArg;
}
function argToObject(inputArg) {
var object = checkObjectCoercible(inputArg);
if (isBoolean(object) || isNumber(object) || isString(object)) {
object = commands.constructor(object);
}
return object;
}
function clamp(number, min, max) {
return Math.min(Math.max(number, min), max);
}
if (isFunction(forEachFN)) {
$.forEach = function (array) {
return forEachFN.apply(array, slice.call(arguments, 1));
};
} else {
$.forEach = function (array, fn, thisArg) {
var object = argToObject(array),
length,
index;
throwIfNotFunction(fn);
for (index = 0, length = clamp(object.length, 0, MAX_UINT32); index < length; index += 1) {
if (hasOwn.call(object, index)) {
fn.call(thisArg, object[index], index, object);
}
}
};
}
if (isFunction(filterFN)) {
$.filter = function (array) {
return filterFN.apply(array, slice.call(arguments, 1));
};
} else {
$.filter = function (array, fn, thisArg) {
var object = argToObject(array),
next,
length,
arr,
index,
element;
throwIfNotFunction(fn);
for (arr = [], next = index = 0, length = clamp(object.length, 0, MAX_UINT32); index < length; index += 1) {
if (hasOwn.call(object, index)) {
element = object[index];
if (fn.call(thisArg, element, index, object)) {
arr[next] = element;
next += 1;
}
}
}
return arr;
};
}
if ('getElementsByClassName' in document) {
$.getElementsByClassName = function (elementNode, className) {
return elementNode.getElementsByClassName(className);
};
} else {
$.getElementsByClassName = function (elementNode, className) {
return $.filter(elementNode.getElementsByTagName('*'), function (element) {
return $.classList.contains(element, className) ? element : privateUndefined;
});
};
}
if (typeof module === 'object' && module && typeof module.exports === 'object' && module.exports) {
module.exports = $;
} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
define($);
} else {
window.$ = $;
}
}());
Javascript - the actual code.
$.forEach($.getElementsByClassName(document, 'normal'), function (element) {
$.addEventListener(element, 'click', function () {
$.classList.toggle(element, 'change');
});
});
On jsFiddle