| 78 | } |
| 79 | |
| 80 | function str(key, holder) { |
| 81 | |
| 82 | // Produce a string from holder[key]. |
| 83 | |
| 84 | var i, // The loop counter. |
| 85 | k, // The member key. |
| 86 | v, // The member value. |
| 87 | length, |
| 88 | mind = gap, |
| 89 | partial, |
| 90 | value = holder[key]; |
| 91 | |
| 92 | // If the value has a toJSON method, call it to obtain a replacement value. |
| 93 | |
| 94 | if (value && typeof value === 'object' && |
| 95 | typeof value.toJSON === 'function') { |
| 96 | value = value.toJSON(key); |
| 97 | } |
| 98 | |
| 99 | // If we were called with a replacer function, then call the replacer to |
| 100 | // obtain a replacement value. |
| 101 | |
| 102 | if (typeof rep === 'function') { |
| 103 | value = rep.call(holder, key, value); |
| 104 | } |
| 105 | |
| 106 | // What happens next depends on the value's type. |
| 107 | |
| 108 | switch (typeof value) { |
| 109 | case 'string': |
| 110 | return quote(value); |
| 111 | |
| 112 | case 'number': |
| 113 | |
| 114 | // JSON numbers must be finite. Encode non-finite numbers as null. |
| 115 | |
| 116 | return isFinite(value) ? String(value) : 'null'; |
| 117 | |
| 118 | case 'boolean': |
| 119 | case 'null': |
| 120 | |
| 121 | // If the value is a boolean or null, convert it to a string. Note: |
| 122 | // typeof null does not produce 'null'. The case is included here in |
| 123 | // the remote chance that this gets fixed someday. |
| 124 | |
| 125 | return String(value); |
| 126 | |
| 127 | // If the type is 'object', we might be dealing with an object or an array or |
| 128 | // null. |
| 129 | |
| 130 | case 'object': |
| 131 | |
| 132 | // Due to a specification blunder in ECMAScript, typeof null is 'object', |
| 133 | // so watch out for that case. |
| 134 | |
| 135 | if (!value) { |
| 136 | return 'null'; |
| 137 | } |