Skip to content

Instantly share code, notes, and snippets.

@brettz9
Created November 10, 2012 05:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brettz9/4050063 to your computer and use it in GitHub Desktop.
Save brettz9/4050063 to your computer and use it in GitHub Desktop.
Shim to allow array-like access on "new String()" characters
<!-- Add our shim to support array-like accessors on
String objects (i.e., those invoked with new String()) -->
<script src="String.js"></script>
<script>
// Regular string literals or String() invoked without 'new' will
// behave the same as without the shim in all browsers (i.e.,
// accessors are not supported in IE < 9)
var str = 'abc';
alert(str[0]); // 'a' in FF, undefined in IE < 9
alert(str.slice(1)); // 'bc'
var str2 = String('abc');
alert(str2[0]); // 'a' in FF, undefined in IE < 9
alert(str2.slice(1)); // 'bc'
// String() with 'new' will, by using the shim,
// behave the same in all browsers (i.e., accessors ARE supported)
var str3 = new String('abc');
alert(str3[0]); // 'a'
alert(str3.slice(1)); // 'bc'
// Still preserves default behavior as far as the String constructor (except that
// it cannot prevent iteration of the String.prototype -- though it can allow
// extension of the prototype before or afterward)
// See https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String#Distinction_between_string_primitives_and_String_objects
var s1 = '2 + 2'; // creates a string primitive
var s2 = String('2 + 2'); // creates a string primitive
var s3 = new String('2 + 2'); // creates a String object
alert(typeof s1); // 'string'
alert(typeof s2); // 'string' (would be 'object' in IE < 9 if we uncommented return line in Str constructor)
alert(typeof s3); // 'object'
alert(eval(s1)); // number 4
alert(eval(s2)); // number 4
alert(eval(s3)); // "2 + 2"
String.prototype.strengthen = function () {
return '<strong>' + this + '</strong>';
};
alert(s3.strengthen()); // <strong>2 + 2</strong>
</script>
(function () {
'use strict';
var i, p, ml, method, methods,
test = String('a');
if (test[0]) {
return;
}
// Inheriting from or iterating over String.prototype is not possible,
// nor does it work to iterate over '' or String instance, so we hard-code
methods = ['charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf',
'localeCompare', 'match', 'replace', 'search', 'slice',
'split', 'substr', 'substring', 'toLocaleLowerCase',
'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase',
'trim', 'valueOf'
];
function addStringMethods (method) {
return function () {
// Using String.prototype gives stack error in IE, so we obtain from our test instance
return test[method].apply(this._str, arguments);
};
}
function Str (str) {
var i, strl;
if (!(this instanceof Str)) {
// Could uncomment the following line to allow String() invocation
// without the "new" keyword, but then "typeof" would not return "string" as expected
//return new Str(str);
return '' + str;
}
str = str + ''; // Ensure converted (avoid converting with String() in case line above uncommented)
this._str = str;
this.length = strl = str.length;
for (i = 0; i < strl; i++) {
this[i] = str.charAt(i);
}
}
for (i = 0, ml = methods.length; i < ml; i++) {
method = methods[i];
if (test[method]) { // Only add if supported (i.e., not trim())
Str.prototype[method] = addStringMethods(method);
}
}
// Default methods shouldn't be iteratable, but we want to grab any user-defined properties/methods
for (method in String.prototype) {
Str.prototype[method] = addStringMethods(method);
}
Str.prototype.constructor = String;
String = Str;
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment