Object#toSourceが便利なんだけど、文字列がエスケープされたままだったりするので、関数で作ってみた

Firefoxでちょこっとチェックしただけです。五分ぐらいで適当に書いているのだけど、毎回毎回書くのは時間の無駄なので。

function toSource(obj, indent) {
	indent = indent || "";

	if (obj === null)
		return indent + "null";
	if (obj === void 0)
		return indent + "undefined";
	if (obj.setTimeout)
		return indent + "[object Window]";
	if (obj.nodeType === 9)
		return indent + "[object Document]";
	if (obj.nodeType)
		return indent + "[object " + (obj.tagName || "") + " Node]";

	var arr = [],
	    type = Object.prototype.toString.call(obj),
	    func = arguments.callee,
	    next_indent = indent + (func.indent || "\t");
	switch (type) {
		case "[object Boolean]":
		case "[object Number]":
		case "[object RegExp]":
		case "[object Date]":
			return indent + obj;
		case "[object String]":
			return indent + '"' + obj.replace(/"/g, '\\"').replace(/\r/g, "\\r").replace(/\n/g, "\\n") + '"';
		case "[object Function]":
			return (indent + obj).replace(/\n/g, "\n" + indent);
		default:
			if (!("length" in obj)) {
				for (var i in obj) {
					arr.push(
						next_indent +
						func(i) + ": " +
						func(obj[i], next_indent).replace(/^\s+/g, "")
					);
				}
				return indent + "{\n" + arr.join(",\n") + "\n" + indent + "}";
			}
		case "[object NodeList]":
		case "[object HTMLCollection]":
		case "[object Arguments]":
		case "[object Array]":
			for (var i = 0, iz = obj.length; i < iz; ++i)
				arr.push(
					func(obj[i], next_indent).replace(/^\s* /g, next_indent)
				);
			return indent + "[\n" + arr.join(",\n") + "\n" + indent + "]";
	}
}