Blog of Jeff A blog about programming and random other things.

22Jul/09link

“Brief” Guide to JavaScript – Part 7

If you haven’t already, check out the previous parts of this series:

Utility Functions

Various functions that are useful when you start doing more than simple JavaScript/DOM manipulation code.

Typeof

Sometimes you'll want to determine what type of data a variable contains, you can use the typeof keyword which returns a string of the type (parenthesizes are optional, but recommended):

typeof('hello world') // => 'string'
typeof 123 // => 'number'
typeof(true) // => 'boolean'
typeof(function(){}) // => 'function'

It's worth mentioning a quirk in typeof with arrays and objects:

typeof([1 2 3]) // => 'object'
typeof({hello: 'world'}) // => 'object'

We'll talk about why when we cover objects in depth, but arrays are actually objects.

Math

As the name suggests, the Math object contains mathematical functions and constants. For convenience, I've copied over the documentation listed at W3Schools. I wish there is more to say about these functions but they're mostly self-explanatory. They come in handy every now and then.

Properties:

  • Math.E - Euler's Constant (~2.718)
  • Math.LN2 - Value of the natural log of 2 (~0.693)
  • Math.LN10 - Value of the natural log of 10 (~2.302)
  • Math.LOG2E - Value of the base-2 log of E (~1.442)
  • Math.LOG10E - Value of the base-2 log of E (~0.434)
  • Math.PI - Circular Constant 22/7 (~3.141)
  • Math.SQRT1_2 - Value of square root of 1/2 (~0.707)
  • Math.SQRT2 - Value of square root of 2 (~1.414)

Methods:

  • Math.abs(x) - Absolute value of x. Converts negative numbers to positive equivalents.
  • Math.acos(x) - ArcCosine (cos-1) of x.
  • Math.atan(x) - ArcTangent (tan-1) of x. Value returned is between -PI/2 and PI/2 radians.
  • Math.atan2(y, x) - Returns angle theta of an (x, y) as a numeric value between -PI and PI radians.
  • Math.ceil(x) - Returns the value of x rounded upwards to the nearest integer.
  • Math.cos(x) - Returns Cosine of x.
  • Math.exp(x) - Returns Ex.
  • Math.floor(x) - Returns the value of x rounded downwards to the nearest integer.
  • Math.log(x) - Returns the natural logarithm (base E) of x.
  • Math.max(x, y) - Returns the highest value of x and y.
  • Math.min(x, y) - Returns the lowest value of x and y.
  • Math.pow(x, y) - Returns xy.
  • Math.random() - Returns a random decimal between 0 and 1.
  • Math.round(x) - Rounds x to the nearest integer.
  • Math.sin(x) - Returns Sine of x.
  • Math.sqrt(x) - Returns square root of x.
  • Math.tan(x) - Returns tangent of an angle x.

Strings

As with everything else in JavaScript strings are objects. There are some functions you may find useful when operating with Strings.

  • str.anchor(anchorid) - A shortcut for creating an a-anchor tag. "My Title".anchor('mytitle') produces <a name="mytitle">My Title</a>.
  • str.link(url) - A shortcut for creating an a-href tag. "Google".link("http://google.com") produces <a href="http://google.com">Google</a>.
  • str.charAt(index) - Gets the character at the specific 0-base index location. Identical to doing str[index].
  • str.toUpperCase() - Returns an uppercase variant of the string. "aBc".toUpperCase() becomes ABC.
  • str.toLowerCase() - Returns a lowercase variant of the string. "aBc".toLowerCase() become abc.
  • str.indexOf(searchStr[, startIndex]) -  Returns the index where searchStr appears in str or -1 if not found.
  • str.replace(searchStr, replaceStr) - Returns a new string of str that replaces the matches of the regular expression of searchStr with replaceStr. You must use regular expressions to replace multiple occurrences of a string. "abccba".replace('a', 'b') produces "bbcba" while "abccba".replace(/a/g, b) produces "bbcbb".
  • str.split(sepStr[, max]) - Returns an array of strings split by sepStr. If an empty string it used, an array of every character of the string is returned. If max is provided, the remaining string will the maximum times the string will be split. "may,june,july".split(",") produces ["may", "june", 'july"].
  • str.match(rexp) - Returns an array of matches found via the regular expression, or null if no matches.

You can view more methods at W3Schools.

 

Timeouts & Intervals

Timers provide an easy way to execute a function at a specified delay. This is done using setTimeout, clearTimeout, setInterval, and clearInterval. setTimeout accepts the function to call and the delay time in milliseconds and returns a timer object which can be passed to clearTimeout to prevent the function from being called. Intervals are like timeouts except that intervals persist, calling the given function every time after a given delay (where as timeouts die after the function is called).

Besides having delays, timeouts and intervals are vital for asynchronous activities as this is the only method, in JavaScript, to do async operations--including animations.

For example, we can fade an element like so:

// quick way to set the property (for IE differences)function opacity(element, value){
    // CSS method of opacity.
    element.style.opacity = value; // 0-1
    if(element.filters){ // IE method of opacity
        element.filters.alpha.opacity = value * 100; // 0-100
    }
}// animate our opacity effect.
function fade(el, start, end, time){
    var curr = start, interv = 13, t = 0;    // how much we should change per interval
    var amt = (end - start) / (time / speed);
    opacity(el, curr); // initial opacity
    var timer = setInterval(function(){
        curr += amt; // new opacity value
        t += interv; // increase time tracker
        opacity(el, curr); // change opacity        // stop animation when we reached out target opacity
        if(t >= time) clearInterval(timer);    // according to john resig, 13 is the min time most browsers will use.    // Lower number is "smoother"
    }, interv); 
}
// usage: fade(document.getElementById('myel'), 0, 1, 1000);// fades in element in 1 second

Animations in JavaScript frameworks are done similar to this method.

Regular Expressions

Another useful feature for any language are regular expressions. Like the DOM tree, regular expressions could have its very own guide. But, unlike the DOM tree, regular expressions are pretty common is higher-level languages, so I'll do a brief overview. After all, this isn't a guide solely for regular expressions.

What are Regular Expressions?

Regular expressions is a way of quickly parsing through a string to find matches, replacements, or just gathering data. For someone who never seen regular expressions, they may appear cryptic. A good reference for getting started with regular expressions is here. Otherwise, prepare for the intense crash course.

Like regular strings, you can match a specific set of letters.

abcdef

Which would only match the string 'abcdef'. By default, regular expressions are case-sensitive, so 'aBcdef' would not be accepted by the expression.

Maybe we want to match a letter from the alphabet, we can do this:

[a-zA-Z]

The square brackets indicates the character must match one of the characters listed inside it. a-z is shorthand for listing all the alphabetical characters where A-Z includes all captial letters.

If we want to match at least one of a particular character, we can use the plus sign.

a+

Which accepts any number of a's (other than zero): 'aaa', 'a', and 'aaaaaaaaaa' all would be accepted.

Star is identical, except it also matches zero of that character:

a*

Accepts everything a+ accepts and no characters (empty string).

Combining what we know, this regular expression is to match only alphabetical characters, which can be done as follows:

[a-zA-Z]+

The + sign indicates that the expression must match one or more of the previous sub-expression (the square brackets, which indicates any alphabetical character).

Having alphanumeric isn't much different.

[a-zA-Z0-9]+

As you can guess, 0-9 represents numbers from 0 to 9.

Shorthand for [0-9], we can use \d to match single digit numbers. So

\d+

Matches any number.

If you just want to match any character known to man, use the dot.

.ell.

This would match 'hello' and 'mello'. But not 'ellot' (no character infront).

Curly braces are used to indicate a more specific value than + or * would provide.

a{3}

Matches only 3 a's. Likewise:

a{3,}

Matches 3 or more a's.

a{,3}

Matches 3 or less a's.

a{3,9}

Matches 3 to 9 a's.

A question mark after a character match indicates an optional match:

abcd?

Matches 'abc' and 'abcd'. If the question mark is used after a + or *, a minimum number of matches is used. This is used to minimize the match range:

a.*c

Would match 'abcabcabc' in the string 'abcabcabc'. Where as:

a.*?c

Would match 'abc' in the string 'abcabcabc'.

Parenthesises are used to group a set of characters as one. Not too significant unless you use other operators

(abc)+

Matches 'abc', 'abcabc', 'abcabcabc', etc.

abc(def)?

Matches 'abc' and 'abcdef'.

So far, most the expressions I've given can match any string that has a substring that matches the expression. So:

[a-z]+

Would accept 'my name is bob', provided matches for 'my', 'name', 'is', 'bob'.

We can provide restrictions than an expression must be at the start of a string or end of a string using ^ and $.

^[a-z]+$

Matches only if the entire string is alphabetical letters. 'mynameisbob' would work, not, 'my name is bob'.

If you want to escape any regular expression special character, use a backslash:

\[hello\]

matches '[hello]'.

That's as much as I'll cover. There are plenty of general-purpose resources on regular expressions you can find via Google.

Now on to the JavaScript specifics of regular expressions.

Constructors

Creating a new regular expression object can be done in two ways. The easiest is using slashes which surround the expression:

var re = /[a-zA-Z]+/;

Alternatively, the new keyword can be used:

var re = new RegExp('[a-zA-Z]+');

The advantage of the latter is being able to use variables, since the constructor accepts a string as the regular expression. In addition, both accept methods can accept additional regular expression flags. The three most common flags are:

  • g - performs a global match. This is used with replace() to replace all occurrences of the expression in a string instead of just the first one.
  • i - performs a case-insensitive match as opposed to the default case-sensitive match.
  • m - performs a multiline match. This makes ^ and $ match the start and end of a line respectively.

Flags are added simply by appending them together:

var rexp1 = /[a-z]+/gi;
var rexp2 = new RegExp('[a-z]*', 'gim');

Using Regular Expressions

The most common uses for regular expressions are used in conjunction with string methods: search, match, replace, and split. Such as replace:

"normal stuff /* comment */".replace(/\/\*.*?\*\//g, '');

This removes your typical multiline comments from strings.

Regular expressions are most commonly used for form validation. An example to check if the user entered a valid email address:

function submitHandler(evt){
    // we're assuming #email_input is the text input where the user entered the email
    var email = document.getElementById('email_input').value;
    if(!email.match(/^[a-zA-Z0-9+._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z]{2,4}(\.[a-zA-Z]{2,4})?$/)){
        alert('Please enter a valid email address!');
        if(evt && evt.preventDefault)
            evt.preventDefault();
        else
            window.event.returnValue = false;
    }
}
// attach submitHandler to the form submit event.

We've covered most of the things here. We have a function that gets the value of the #email_input element (presumably an input field), check if it matches our regular expression, and stop the form from submitting if it doesn't.

Let's breakdown the regular expression monstrosity:

^[a-zA-Z0-9+._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z]{2,4}(\.[a-zA-Z]{2,4})?$

^ indicates that the expression has to match from the very beginning of the string.

[a-zA-Z0-9+._-] allows any alphanumeric, hypen, period, plus, or underscore character.

+ requires at least one character (that matches the above requirements) but can be more than that. In conjunction with [a-zA-Z0-9+._-], we match the username portion of the email address.

@ is simply the text we're looking for: the @ symbol of the email.

[a-zA-Z0-9._-] allows any alphanumeric, hypen, period or underscore character.

+ again, matches the previous expression at least one time.

\. escapes the normal regular expression behavior of the period. Here we just match a period character.

[a-zA-Z] We match an alphabetical character.

{2,4} two to four times. So 'a' would not work, but 'aa' would. This helps match a domain name extension for us (eg - .com, .net, etc.)

(\.[a-zA-Z]{2,4}) Here we do that again, because there are domains with two dots (eg - .co.uk) and we need to check for those too. In this case, we're creating it as a group because...

? We make the matching requirement optional. Allowing the traditional domain name extensions to still work.

$ Indicates we should be at the end of the string now.

Admittedly, some invalid emails will get through, but the point of validation is to help filter the invalid data from entering our system while not hindering possible valid entries.

Using Regular Expressions (from the Perl/Ruby Camps)

If you're used to a programming language like Perl and Ruby, which have more convenient ways of doing loops, use RegExp.exec(), which returns the text if a match is found and null if otherwise.

But the main advantage of exec is it automatically fills the special variables:

RegExp.$1
RegExp.$2

... all the way to ...

RegExp.$9

These special variables are filled with groups. Groups are either the entire regular expression matching or subexpressions in parenthesizes (), which allow us to "capture" text in certain locations in an expression.

As usual, examples always speak better than documentation:

var re = /^(http:\/\/)?(([^ .]+)\.)?([^ .]+)\.([^ .]{2,4})(\/[^ ]*)?$/;
var input = prompt('Enter some URL:');
if(input){
    if(re.exec(input)){
        alert('Subdomain: '+RegExp.$3 + '\n' +
                 'Domain: ' + RegExp.$4 + '.' + RegExp.$5);
    } else {
        alert('Invalid URL');
    }
} else {
    alert('No Input');
}
//

There are also some other new things. First the regular expressions:

[^ .]

The carrot at the beginning makes the matching exclusive. So this would match any character that isn't a space or period.

prompt(message[, default])

Prompt displays a browser-provided dialog input with your message and a space for the user to enter input. An optional default parameter can be filled to provide default input. I don't usually recommend using this function in production for usability issues. The function returns the text the user entered.

We then call our exec function on the given input string to parse. If there was no match, we execute the else statement.

After calling exec, The special RegExp variables are filled. To figure out which grouping you want, count the number of parenthesizes.

$1 is for the http:// or blank if not existant

$2 is the subdomain, including the period at the end

$3 is the subdomain without the period

$4 is the domain name

$5 is the domain name extension

$6 is everything after the domain name part of the URL.

Remember that this numbering only goes up to $9, so try not to have too many groupings in your expression.

As anything, experimentation will solidify your understanding more than me yapping away.


That wraps it up. Next, we’ll talk about some more advanced topics that are lesser used if programming isn’t your normal cup-of-tea. Read part 8.

  • Share/Bookmark
blog comments powered by Disqus

Recent Posts

Topics

Archives

Following

Links