Vous êtes sur la page 1sur 11

JavaScript on xunRAGE™ Blog

String pad function in JavaScript

I've found this mind blowing function for padding a string in JavaScript:

String.prototype.pad = function(l, s, t){


return s || (s = " "), (l -= this.length) > 0 ? (s = new
Array(Math.ceil(l / s.length)+ 1).join(s)).substr(0, t = !t ? l : t ==
1 ? 0 : Math.ceil(l / 2))+ this + s.substr(0, l - t) : this;
};

Let's break it in pieces:

The construction String.prototype.pad = function(l, s, t) extends the functionality of the String


object adding a new method called pad, which is a function that has three parameters.

Parameters of the function stand for: l=maximal length of the string, s=padding string and
t=type of padding (0=left, 1=right and 2=center).

An expression which contains an enumeration is evaluated to the last member of the


enumeration; therefore the second expression in the return clause will be the result of the
function.

A logical OR expression is evaluated until a member is true, therefore the expression s || (s=" ")
actually means: if s contains something then it is true and left alone, otherwise s will contain
exactly one space.

Expression (l-=this.length) makes l contain the number of needed characters for the string to
have the required length (if the length of the string is 7 and we want it padded to 20 characters,
now the l is 13).

Is well known the expression like <logical> ? <value_for_true> : <value_for_false>.

If new l is greater than 0, then computations are required, otherwise the string (referenced
using this) is returned as it is.

Math.ceil(<value>) gives the closest upper integer value of the given value.

1
join(<separator>) creates a single string value from the array it is applied to using the given
separator string.

The expression s=new Array(Math.ceil(l/s.length)+1).join(s) creates a new array with a number


of elements equal to the number of times s is required to repeat for the string to be padded,
plus one (because there are -1 separators involved in such a join), then the empty values are
joined using s as a separator. The new value is now assigned to s. For example, if we want the
string "xunrage" padded with s="{}" to the left (t=0) for a total length of l=20, first l became 13,
and now l/s.length=13/2=6.5, therefore Math.ceil(l/s.length)=7, following that a new array with
8 elements will be created. When joined, only 7 separators forms the result, therefore
s="{}{}{}{}{}{}{}".

substr(<start>,<length>) returns a portion of a string that the function is applied to starting at


the given position and having the given length.

Expression substr(0, t=!t ? l : t == 1 ? 0 : Math.ceil(l/2)) contains two ?: expressions and an


assignment in the second parameter of the substr function. The first expression is !t ? l :
<the_rest> and the second expression is t==1 ? 0 : Math.ceil(l/2). The value of the entire
expression at the end is assigned to t. In our example t=0, therefore !t is true and t=l=13,
resulting a string like "{}{}{}{}{}{}{" that will be added to the result.

Finally, if something left to be added is added at the end, using substr again. For left padding
(t=0) there is nothing left to be added because t=l=13 and l-t=0, resulting in
"{}{}{}{}{}{}{xunrage". For right padding t=1, we have t=0 initially (t==1 ? 0 : ...) and l-t=13 at the
end, resulting in "xunrage{}{}{}{}{}{}{". For center padding t=2 and we have t=Math.ceil(l/2)
which is t=Math.ceil(13/2)=Math.ceil(6.5)=7, finally l-t=13-7=6, resulting in "{}{}{}{xunrage{}{}{}".

Now you can see how amazing this one line of code is.

2
Functions in JavaScript
A Delphi programmer like me, accustomed with strongly typed programming, with clear
function block limitation and with classic object oriented style, finds JavaScript overwhelmingly
weird. In JavaScript a variable type is interpreted and can happily jump from one type to
another, object oriented is based on prototyping starting from the Object primitive type and
functions are objects derived from Object.

The Object type has two properties (constructor, prototype) and six methods (eval, toSource,
toString, unwatch, valueOf, watch) (see http://docs.sun.com/source/816-6408-10/object.htm).

Function is a type descended from Object and has six more properties (arguments,
arguments.callee, arguments.caller, arguments.length, arity, length) and two methods (apply,
call) (see http://docs.sun.com/source/816-6408-10/function.htm).

Below are some code snippets:

Creating an object is as follows:

var myObject = new Object();

or

var myObject = { }

In the second notation, the members of the object are expressed like name:value pairs as:

var myObject = { aname : 15, bname: "test" }

Such a member can be a function like:

var myObject = { myfunc: function(msg){ return msg+msg; } }

A function can be created also as follows:

var f = new Function("a","b","return a+b;");

To create a simple object is used the special keyword this:

function myType(a,b,c){
this.a=a;
this.b=b;
this.c=c;
}

3
Then you can use this object like:

var f = new myType(10," and ",20);


document.write(f.a + f.b + f.c); // The result is 10 and 20

Create an object with a method:

function myType(a,b){
this.a=a;
this.b=b;
this.add = function(){ with(this) return a+b; }
}

Now use the object:

f = new myType(5,6);
document.write(f.add()); // The result is 11

Note that the add method is present in any object created and if there are 1000 instances of
myType, there are also 1000 instances of the function add. To avoid this, use the prototype
keyword like this:

function myType(a,b){
this.a=a;
this.b=b;
}
myType.prototype.add = function(){ return this.a + this.b; }

Use it like previously explained:

f = new myType(19,11);
document.write(f.add()); // The result is 30
There can be created a helper function like:

Function.prototype.method = function (name, func) {


this.prototype[name] = func;
return this;
};

The simple object:

function myType(a,b){
this.a=a;
this.b=b;
}

4
Add a new method like this:

myType.method("add", function(){ return this.a+this.b; });


Then use it as usual:
f = new myType(125,80);
document.write(f.add()); // The result is 205

Some more JavaScript

Some quick tips:

To continue a string on the next line in JavaScript, use the \ operator like this:

var s = "A long text \


that continues on the next line";

Create on the fly functions like this:

function functionAssembler(operatorSign){
return new Function("a","b","return a" + operatorSign + "b;");
}
Use it to create functions:

var add = functionAssembler("+");


var substract = functionAssembler("-");
var multiply = functionAssembler("*");
var divide = functionAssembler("/");
Use the function as always:

document.write(add(10,5));
document.write(substract(12,6));
document.write(multiply(5,3));
document.write(divide(125,5));

5
Detecting Internet Explorer version with Javascript

I have found on the Internet the following function for detecting Internet Explorer version:

function vIE(){return (navigator.appName=='Microsoft Internet


Explorer')?parseFloat((new RegExp("MSIE ([0-9]{1,}[\.0-
9]{0,})")).exec(navigator.userAgent)[1]):-1;}

The property navigator.appName returns something like: Opera

The property navigator.userAgent returns something like: Opera/9.80 (Windows NT 6.1; U; en)
Presto/2.6.30 Version/10.63

The function returns the conditional result of the expression <logical> ? <value_for_true> :
<value_for_false>

Constructor RegExp creates a new object and defines a regular expression as: [0-9] defines a
character set formed by any character in the range 0-9; {x,} defines the minimum x number of
occurrences used in the match; () creates a sub expression.

RegExp.exec(string) returns an array of the matches of the regular expression in the given string
or null if no match is found. The returned array contains both matches for the regular
expression as well as for present sub expressions. For this reason, the second element in the
array is parsed to a float value and returned by the function.

A use of the function above:

<script language="javascript" type="text/javascript">


function vIE(){
return (navigator.appName=='Microsoft Internet Explorer') ?
parseFloat((new RegExp("MSIE ([0-9]{1,}[\.0-
9]{0,})")).exec(navigator.userAgent)[1]):-1;
}
function isIE8(){
if(vIE()==7){
if(navigator.userAgent.indexOf("Trident/4.0")==-1) return false;
else return true;
} else{
if(vIE()==8) return true;
else return false;}
}

6
if(vIE()<0){
document.write("N/A");}
else{
if(isIE8()){
document.write("8");
if(vIE()==7) document.write(" (Compatibility View)");
}
else{ document.write(vIE()); }
}
</script>

Test Java Presence


To detect if Java is enabled on your computer use the following code:

if(navigator.javaEnabled()){ ... }

Static variable in a Javascript object function


Consider the code bellow:

function myfunction(){
var myvariable=19.21;
this.mymethod = function(){ return myvariable; };
this.increase = function(amount){ myvariable+=amount; };
}
var f = new myfunction();
document.write("initial value is " + f.mymethod());
f.increase(0.80);
document.write("<br/>new value is " + f.mymethod());

Because the function myfunction is used as a class for the object f, the local variable myvariable
is considered private and it can be accessed only by member functions like mymethod and
increase.

7
Javascript object functions runs on creation
Consider the code bellow:

function myfunction(){
document.write("I was executed.");
}
var f = new myfunction();

The function myfunction is used as a class for the object f, and is also executed at creation time.

Hello world form

<form style="background-color: #e3e3e3; color: black;


width:450px; font-family:courier new; text-align:center;"
action="">
<input type="button" value="Hello world!" onclick="sayhello();">
</form>
<script language="javascript" type="text/javascript">
function sayhello(){
alert("Hello world!");
}
</script>

Script Integration Test


The main problem when writing a JavaScript inside a blogger post is that the editor interprets <
and > as portions of html tags, even if they are inside the <script> tag. The solution presented
as an example here is to create two string variables called lt and gt and use them instead. On
the other hand, to write the code only once, it is put inside a string variable and then evaluated.
To display it properly the two conflicting characters should be transformed again using a
function that replaces their occurrences. You may also be aware that the code should be on a
single line, because a new line creates html markup inside the script.

The following script is evaluated:


8
var a=new Array(); a=[1,2,3,4]; for(i=0; i<a.length; i++)
document.write(a[i]+(i==a.length-1?"":", "));

The full code:

<script language="javascript" type="text/javascript">


var lt=String.fromCharCode(0x003c);
var gt=String.fromCharCode(0x003e);

function escapeltgt(s){
s=s.replace(lt,"&"+"lt;");
s=s.replace(gt,"&"+"gt;");
return s;
}

var s="var a=new Array(); a=[1,2,3,4]; for(i=0; i"+lt+"a.length;


i++) document.write(a[i]+(i==a.length-1?\"\":\", \"));";
document.write("The following script is evaluated:<br/>" +
escapeltgt(s)+"<br/><br/>And the result is:<br/>");
eval(s);
</script>

Naming conventions
When someone like me puts a lot of markup and javascript inside posts there is always a risk to
create conflicting ids and names. One solution is to create a naming convention. Therefore a
good idea will be to create master functions (or classes if you like) that contain all the javascript
code, and the markup to be inserted using javascript also. The class function will have a name
like xunClass_12345678, the instance of the class the name like xunInstance_12345678, while
markup elements something like xun[Markup]_12345678_1234, where 12345678 is a unique
alphanumeric id for the class and is identical for the instance and any markup, while for markup
the last 1234 is a unique id in that area. See the source code for this post for an example.

Markup:

<div id="xunDiv_f9s6k7x1_a1y9" align="center"


style="background-color:#e3e3e3; width:450px; height:45px;
font-family:Courier New,monospace; font-size:12px;
line-height:15px;"></div>

9
And this is how it is done:

<script language="javascript" type="text/javascript">


function xunClass_f9s6k7x1(){
this.id = "f9s6k7x1";

var lt=String.fromCharCode(0x003c);
var gt=String.fromCharCode(0x003e);
var quot=String.fromCharCode(0x022);

function replaceall(s,matchString,replaceString){
var olds = s;
s = olds.replace(matchString,replaceString);
while(s!=olds){
olds = s;
s = olds.replace(matchString,replaceString);
}
return s;
}

function escapeltgtquot(s){
s = replaceall(s,lt,"&"+"lt;");
s = replaceall(s,gt,"&"+"gt;");
s = replaceall(s,quot,"&"+"quot;");
return s;
}
function putquotes(s){
return replaceall(s,"^",quot);
}

var divid = "xunDiv_" + this.id + "_a1y9";


var br = lt+"br/"+gt;

s = lt + "div id=^"+divid+"^ align=^center^ style=^background-


color:#e3e3e3; width:450px; height:45px; font-family:Courier
New,monospace; font-size:12px; line-height:15px;^"+gt+lt+"/div"+gt;
s = putquotes(s);
document.write("Markup: "+br+escapeltgtquot(s)+br+br);
document.write(s);

var e = document.getElementById(divid);
e.innerHTML=br+"hello from " + divid;
}
var xunInstance_f9s6k7x1 = new xunClass_f9s6k7x1();
</script>

10
Child Div
Below is a div with the border dashed and using javascript a new div is added as its child.
Internet Explorer is a bit different from Firefox and the others when it comes to this DOM
action. I took style information from

http://msdn.microsoft.com/en-us/library/ms535240(VS.85).aspx.

The code:

<div align="center" id="containerdiv9"


style="background-color: white; border: 1px dashed black;
height: 150px; width: 450px;">
</div>
<script language="javascript" type="text/javascript">
var d = document.createElement("div");
d.setAttribute("id","forgediv");
d.setAttribute("style","width:300px; height:100px; background-
color:#e3e3e3; border:1px solid black; position:relative; top:25px;");
// set style in IE
d.style.backgroundColor='#e3e3e3';
d.style.width='300px';
d.style.height='100px';
d.style.border='1px solid black';
d.style.position='relative';
d.style.top='25px';
document.getElementById("containerdiv9").appendChild(d);
</script>

11

Vous aimerez peut-être aussi