引数に渡された値を詳細に表示

初投稿です。
タイトルのような関数を作ってみました。

一定のコーディング規約を決めて書きました。
ソースコードは全て英語ですが、英和/和英辞典で調べて、それっぽいものを使っただけです。
変な英語表現がありましたら、教えて下さい。（一杯ありそうです）

使い方

```js
 debug([1,2])
```

 とすると、

```
 [
     1,
     2
 ]
```

 という感じです。
 使ってみれば分かります。
 オプションでは、indent(インデント) と depth(階層) が指定できます。
 depth 0 では、階層の概念なし、ということで、オブジェクトを完全に展開します。
 debug([1,2],{depth:0}) とすれば、上記と同じ内容が返ります。
 depth 1 では、1階層分の展開しかしません。
 debug([1,2],{depth:1}) とすれば、[object Array] が返ります。
 depth 2 では 上記と同じ内容が返ります。
 これ、説明し辛いです。

 indent は、その名の通り、インデントの文字を指定できます。
 '  ' を指定すれば、空白2つ分ですし、
 '\t' を指定すれば、水平タブ1つ分です。
 '___' こんなのでも指定できます。

それから、DOM 辺りの扱いが適当です。
window なんかも、エラー出ないようにに取り繕いました。


```js
/* option
	.indent
		'': no indent
		'  ': indent with '  '
	.depth
		0: all expand (no - depth)
		1: no expand (depth 1)
		2: 1 expand (depth 2)
*/
(function(global, undef){
'use strict';
var
	toString = Object.prototype.toString,
	hasOwnProperty = Object.prototype.hasOwnProperty,

	Indent,
	MaximumDepth,

	// Boolean
	limitDepth;
var makeSource = function (CurrentDepth, stack, value) {
	var

		// Boolean
		circulated,

		// String
		currentIndent = '',

		// Number
		formerDepth,
		i,
		index,
		length,
		stackLength,

		// Object
		array,
		attributes,
		constructor,

		// Node for NamedNodeMap
		node;

	// undefined null
	switch (value) {
	case undef:
		return 'undefined';
	case null:
		return 'null';
	default:
		break;
	}

	try {
		constructor = value.constructor;
	} catch (e) {
		return '[' + toString.call(value) + ']';
	}

	// Not (DOM | Window)
	if ('function' === typeof constructor) {
		switch (toString.call(value)) {
		case '[object Boolean]':
			return value.toString();
		case '[object String]':
			return '\'' + value.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + '\'';
		case '[object Number]':
			return value.toString();
		case '[object Date]':
			return value.toGMTString();
		case '[object RegExp]':
			return value.toString();
		case '[object Function]':
			return 'function ' + (value.name || '');
		case '[object Array]':
			// Limit Depth
			if (MaximumDepth && CurrentDepth >= MaximumDepth) {
				return '[object Array]';
			}

			// Check Circular Reference
			circulated = false;
			i = stackLength = stack.length;
			while (i--) {
				if (value === stack[i]) {
					circulated = true;
					break;
				}
			}
			if (circulated) {
				return 'circular referenced Array';
			}

			// Push Stack
			stack[stackLength] = value;

			// make indent
			i = CurrentDepth;
			while (--i) {
				currentIndent += Indent;
			}

			// make source again
			array = [];
			length = value.length;
			for (i = 0; i < length; ++i) {
				array[i] = '\n' + currentIndent + Indent + makeSource(CurrentDepth + 1, stack, value[i]);
			}

			// Pop Stack
			stack.length = stackLength;

			return '[' + array.join(',') + '\n' + currentIndent + ']';
		case '[object Object]':
			// Limit Depth
			if (MaximumDepth && CurrentDepth >= MaximumDepth) {
				return '[object Object]';
			}

			// Check Circular Reference
			circulated = false;
			i = stackLength = stack.length;
			while (i--) {
				if (value === stack[i]) {
					circulated = true;
					break;
				}
			}
			if (circulated) {
				return 'circular referenced Object';
			}

			// Push Stack
			stack[stackLength] = value;

			// make indent
			i = CurrentDepth;
			while (--i) {
				currentIndent += Indent;
			}

			// make source again
			index = 0;
			array = [];
			for (i in value) {
				if (hasOwnProperty.call(value, i)) {
					array[index++] = '\n' + currentIndent + Indent + '\'' + i.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + '\': ' + makeSource(CurrentDepth + 1, stack, value[i]);
				}
			}

			// Pop Stack
			stack.length = stackLength;

			return '{' + array.join(',') + '\n' + currentIndent + '}';
		default:
			break;
		}
	} else {
		switch (value.nodeType) {
		// ELEMENT_NODE
		case 1:
			// Limit Depth
			if (MaximumDepth && CurrentDepth >= MaximumDepth) {
				return '[' + toString.call(value) + ']' + ' (nodeType - ' + value.nodeType + ')';
			}

			// make indent
			i = CurrentDepth;
			while (--i) {
				currentIndent += Indent;
			}

			// make source again
			if (length = (attributes = value.attributes).length) {
				array = [];
				for (i = 0; i < length; ++i) {
					array[i] = '\n' + currentIndent + Indent + makeSource(CurrentDepth + 1, stack, attributes[i]);
				}
				return '[' + value.toString() + ']' + '{' + array.join(',') + '\n' + currentIndent + '}';
			} else {
				return '[' + value.toString() + ']';
			}
		case 2:
			return 'ATTRIBUTE_NODE{' + value.name + ': ' + value.value + '}';
		case 3:
			return 'TEXT_NODE[' + value.nodeValue + ']';
		case 4:
			return 'CDATA_SECTION_NODE[' + value.nodeValue + ']';
		case 5:
			return 'ENTITY_REFERENCE_NODE[' + value.nodeValue + ']';
		case 6:
			return 'ENTITY_NODE[' + value.nodeValue + ']';
		case 7:
			return 'PROCESSING_INSTRUCTION_NODE[' + value.nodeValue + ']';
		case 8:
			return 'COMMENT_NODE[' + value.nodeValue + ']';
		case 9:
			return 'DOCUMENT_ELEMENT(document)';
		case 10:
			return 'DOCUMENT_TYPE_NODE';
		case 11:
			return 'DOCUMENT_FRAGMENT_NODE';
		case 12:
			return 'NOTATION_NODE';
		// NamedNodeMap
		default:
			if (undef !== value.getNamedItem) {
				// make indent
				i = CurrentDepth;
				while (--i) {
					currentIndent += Indent;
				}

				// make source again
				if (length = value.length) {
					array = [];
					for (i = 0; i < length; ++i) {
						array[i] = '\n\'' + (node = value[i]).name.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + '\': \'' + (node.value || '').replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + '\'';
					}
					return 'NamedNodeMap' + '{' + array.join(',') + '\n' + currentIndent + '}';
				} else {
					return 'NamedNodeMap';
				}
			}
			break;
		}
	}

	// Limit Depth
	if (limitDepth || MaximumDepth && CurrentDepth >= MaximumDepth) {
		return '[' + toString.call(value) + ']';
	}

	if (undef === (length = value.length)) {
		// Others
		return '[' + toString.call(value) + ']' + ' (Stranger)';
	} else {
		if ('number' === typeof length && hasOwnProperty.call(value, length - 1)) {
			// Check Circular Reference
			circulated = false;
			i = stackLength = stack.length;
			while (i--) {
				if (value === stack[i]) {
					circulated = true;
					break;
				}
			}
			if (circulated) {
				return 'circular referenced Arrayed Stranger';
			}

			// Push Stack
			stack[stackLength] = value;

			// make indent
			i = CurrentDepth;
			while (--i) {
				currentIndent += Indent;
			}

			// limit depth
			limitDepth = true;

			// make source again
			length = value.length;
			array = [];
			for (i = 0; i < length; ++i) {
				array[i] = '\n' + currentIndent + Indent + makeSource(CurrentDepth + 1, stack, value[i]);
			}

			// free depth
			limitDepth = false;

			// reposit MaximumDepth
			MaximumDepth = formerDepth;

			// Pop Stack
			stack.length = stackLength;

			return '[' + toString.call(value) + ']' + '[' + array.join(',') + '\n' + currentIndent + ']';
		} else {
			// Check Circular Reference
			circulated = false;
			i = stackLength = stack.length;
			while (i--) {
				if (value === stack[i]) {
					circulated = true;
					break;
				}
			}
			if (circulated) {
				return 'circular referenced Objected Stranger';
			}

			// Push Stack
			stack[stackLength] = value;

			// make indent
			i = CurrentDepth;
			while (--i) {
				currentIndent += Indent;
			}

			// limit depth
			limitDepth = true;

			// make source again
			index = 0;
			array = [];
			for (i in value) {
				if (hasOwnProperty.call(value, i)) {
					array[index++] = '\n' + currentIndent + Indent + '\'' + i.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + '\': ' + makeSource(CurrentDepth + 1, stack, value[i]);
				} else {
					array[index++] = '\n' + currentIndent + Indent + '\'' + i.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + '\': ' + makeSource(CurrentDepth + 1, stack, value[i]) + ' (prototype)';
				}
			}

			// free depth
			limitDepth = false;

			// Pop Stack
			stack.length = length;

			return '[' + toString.call(value) + ']' + '{' + array.join(',') + '\n' + currentIndent + '}';
		}
	}
};
global.debug = function (object, option) {
	var hasOwnProperty = Object.prototype.hasOwnProperty;

	/* option */
	if (option) {
		// String indent
		if (hasOwnProperty.call(option, 'indent')) {
			Indent = option.indent;
		} else {
			Indent = '   ';
		}

		// Number depth
		if (hasOwnProperty.call(option, 'depth')) {
			MaximumDepth = option.depth;
		} else {
			MaximumDepth = 0;
		}
	} else {
		Indent = '   ';
		MaximumDepth = 0;
	}

	return makeSource(1, [], object);
};
})(this);
```