Extending Native String

Strings in JavaScript do not have as many helper functions as one might like. As a result you will probably need to write a collection of methods yourself. You can either create a static utility object (or functional functions) or extend the "String.prototype". String is one of the few objects that has little consequence when extending its prototype object, as you do not use "for … in" on strings.

For today’s discussion, we will be using YAHOO.lang.augmentObject to augment the String.prototype, which is a simple method that adds the values of the object passed as the second argument onto the object passed as the first argument. For more information, see YUI yahoo.js.

Next we need to consider what functionality is most needed and missing: word capitalization, stripping characters (alpha, numbers, etc…), stripping tags (script, or all html tags), and trimming white spaces. You may want a lot more, but those are the ones I use most.

Article updated on Jan. 29, 2013

Most experts will say it is bad practice to extend native JavaScript objects. Consider creating a var StringUtils = {…}; static object instead of augmenting String.prototoype.

How do it…

Here we extend String.prototype with additional helper functions:

YAHOO.lang.augmentObject(String.prototype, {

	/**
	 * Capitolize the first letter of every word; ucfirst, ensures that all non-first letters are lower-case
	 * @method capitalize
	 * @param ucfirst {boolean} OPTIONAL: when truthy, converts non-first letters to lower-case
	 * @return {string} the converted string
	 * @static
	 */
	capitalize: function(ucfirst) {
		var words = this.split(/\b/g),
			rs = [];

		Core.batch(words, function(w, i) {
			if (w.trim()) {
				rs[i] = w.charAt(0).toUpperCase() + (ucfirst? w.substring(1).toLowerCase(): w.substring(1));
			}
		});

		return rs.join(" ");
	},

	/**
	 * Checks if a string contains any of the strings in the arguement set
	 * @method contains
	 * @param argument {string} as many strings you want to test
	 * @return {boolean} true, if string contains any of the arguements
	 * @static
	 */
	contains: function() {
		var hasValue = false;

		Core.batch(arguments, function(arg) {
			hasValue = -1 < str.indexOf(arg); // terminates iteration if this becomes true
			return hasValue;
		});

		return hasValue;
	},

	/**
	 * Removes the rx pattern from the string
	 * @method remove
	 * @param rx {regex} a regex to find characters to remove
	 * @public
	 */
	remove: function(rx) {
		return this.replace(rx, "");
	},

	/**
	 * Remove all non-alpha characters;space ok
	 * @method stripNonAlpha
	 * @public
	 */
	stripNonAlpha: function() {
		return this.remove(/[^A-Za-z ]+/g);
	},

	/**
	 * Remove all non-alpha-numeric characters; space ok
	 * @method stripNonAlphaNumeric
	 * @public
	 */
	stripNonAlphaNumeric: function() {
		return this.remove(/[^A-Za-z0-9 ]+/g);
	},

	/**
	 * Removes non-numeric characters, except minus and decimal
	 * @method stripNonNumeric
	 * @public
	 */
	stripNonNumeric: function() {
		return this.remove(/[^0-9\-\.]/g);
	},

	/**
	 * Remove all characters that are 0-9
	 * @method stripNumeric
	 * @public
	 */
	stripNumeric: function() {
		return this.remove(/[0-9]/g);
	},

	/**
	 * HTML script tags from the string
	 * @method stripScripts
	 * @public
	 */
	stripScripts: function() {
		return this.remove(new RegExp("(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)", "img"));
	},

	/**
	 * HTML tags from the string
	 * @method stripTags
	 * @public
	 */
	stripTags: function() {
		return this.remove(/<\/?[^>]+>/gi);
	},

	/**
	 * Replaces the white spaces at the front and end of the string
	 * OPTIMIZED: http://blog.stevenlevithan.com/archives/faster-trim-javascript
	 * @method trim
	 * @public
	 */
	trim: function() {
		return this.remove(/^\s\s*/).remove(/\s\s*$/);
	}
});

If you decided to use a static object instead, it would be:

var StringUtils = {
    // copy object from second argument above
};

How it works…

Most of these functions are pretty easy to understand, especially if you look at my comments (feel free to leave a comment if you have questions). The best part is, because you have extended "String.prototype", so every String throughout your entire project will be able to use them. Often times, you will find tasks that are specific toward the current project, but maybe not relevant to every project. For example, Mint.com is a financial site where I often need to search for numbers and/or currency, so I have special methods for that project. It is best to keep project specific modifications in a separate file and bring them into your project as necessary.

There’s more…

Some of these methods that are frequently used, such as trim, have been heavily optimized. As you can see, many string manipulations can/should be handled by regex, so it is a good idea to understand regex (hopefully you do). Steven’s Blog is a great place for your regex questions, especially when looking for the best way to write an expression.