====== Javascript ====== ===== Links == [[http://de.selfhtml.org/javascript/objekte/|Selfhtml]] - [[https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide|JavaScript 1.5 Guide]] - [[https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference|JavaScript 1.5 Reference]] - [[https://developer.mozilla.org/en/Gecko_DOM_Reference|Gecko DOM Reference]] - [[http://msdn.microsoft.com/en-us/library/ms533050%28VS.85%29.aspx|M$ HTML and DHTML Reference]] - [[Dojo]] - [[html5]] - [[jrunscript]] ===== Variables == ==== var Keyword == Within functions always prefix variables with ''var'', otherwise they become global! See [[http://dojotoolkit.org/book/dojo-book-0-9/part-3-programmatic-dijit-and-dojo/modules-and-namespaces|Avoid Global namespace]] ===== Strings == A string can be an instance of the ''String'' class or a string literal. [[https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Objects#String_Object|More]] ==== String Literals == There is no difference between ''%%'A string'%%'' and ''%%"A string"%%'' [[https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Values%2c_Variables%2c_and_Literals#String_Literals|More]] A string literal is temporarely converted into a ''String'' object as soon as you apply methods of ''String'' class to the string literal. ==== Creating Strings == var s1 = "foo"; //creates a string literal value var s2 = new String("foo"); //creates a String object [[https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Objects#String_Object|More]] ==== String Concatenation == var a= "al" + "pha" // a == "alpha" a += "bet" // a = "alphabet" ==== String Comparison == FIXME Because Strings are ojects, String comparison is the same as object comparison :?: ==== String Methods/Property == String length: ''var len = mystring.length;'' [[https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Objects#String_Object|All string methods]] ===== Arrays == An Array is an instance of the ''Array'' class. [[https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Arrays|More]] ==== Creating Arrays == var arr= new Array(element0, element1, ..., elementN); var arr= [element0, element1, ..., elementN]; var arr= new Array(arrayLength); var arr= []; ==== Array Methods/Property == Array length: ''var len = myarray.length;'' [[https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Arrays#Array_methods|Array Methods]] ===== Objects and Inheritance ===== ==== Object creation == === The classic Java-like way == function Point(x, y) {this.x=x; this.y=y;} Point.prototype.toString = function() {return "("+this.x+"/"+this.y+")";} Point.prototype.shift = function(dx, dy) {this.x+=dx; this.y+=dy;} var p = new Point(3,4); document.write("p:"+p.toString()); === The closure way == (closures see below) function makePoint(x, y) { return { toString: function() {return "("+x+"/"+y+")";} shift: function(dx, dy) {x+=dx; y+=dy;} };} var p = makePoint(3,4); document.write("p:"+p.toString()); FIXME * This variant is to be verified * Does this cause overhead? * What about inheritance? === Object literals == FIXME ==== Object cloning == Objects are [[http://www.thescripts.com/forum/thread718427.html|passed by refernce]] => Something like a copy constructor is necessary: function Point(x, y) {this.x=x; this.y=y;} Point.prototype.clone= function() {return new Point(this.x, this.y);} Point.prototype.toString= function() {return "("+this.x+"/"+this.y+") ";} var p = new Point(3,4); var pr = p; // a reference to p var q = p.clone(); // a new Point instance with the same coordinates as p p.x= 9; p.y=-2; // change content of p document.write("p:"+p.toString()+ "pr:"+pr.toString()+ "q:"+ q.toString()); // result: p:(9/-2) pr:(9/-2) q:(3/4) ==== Object Comparison == FIXME ==== Defining Methods ==== === Method definition inline inside of the constuctor === function MyClass() { // constructor this.method1= function(arg) {/* code */}; // method } * Seems to cause overhead, see [[http://phrogz.net/JS/Classes/OOPinJS.html|OOP in JS, Part 1 : Public/Private Variables and Methods]] * This is callad a privileged method (which has access to private methods, see below) === External method definition and link to object inside of the constructor == function MyClass_method1(arg) {/* code */} // method function MyClass() {this.method1= MyClass_method1} // constructor Not recommendable, because * its not easy to see to which object the method definitions belong to * method definitions could be called directly whitout existing ''this'' === External method definition and link to object outside of the constructor === function MyClass() {} // constructor MyClass.method1= function(arg) {/* code */} // method Not possible, causes an js-error if called from an MyClass //instace//. This is a static method, see below === External method definition and link to object outside of the constructor with prototype === function MyClass() {} // constructor MyClass.prototype.method1= function(arg) {/* code */} // method Seems to be the **best** solution :-) ==== Public Access == function MyClass() { // The constructor this.publicVariable= 10; // A public instance variable } MyClass.prototype.publicMethod= function() { // A public (instace) method document.write(this.publicVariable + 1 + ' '); document.write(MyClass.publicVariable + 1 + ' '); document.write(this.publicStaticVariable + 1 + ' '); document.write(MyClass.publicStaticVariable + 1 + '
'); } MyClass.publicStaticVariable = 20; // A public class variable MyClass.publicStaticMethod= function() { // A public class method document.write(this.publicVariable + 2 + ' '); document.write(MyClass.publicVariable + 2 + ' '); document.write(this.publicStaticVariable + 2 + ' '); document.write(MyClass.publicStaticVariable + 2 + '
'); } // Test: var myclass= new MyClass(); document.write(myclass.publicVariable + '
'); // 10 document.write(MyClass.publicVariable + '
'); // undefined myclass.publicMethod(); // 11 NaN NaN 21 //MyClass.publicMethod(); // error! document.write(myclass.publicStaticVariable + '
'); // undefined document.write(MyClass.publicStaticVariable + '
'); // 20 //myclass.publicStaticMethod(); // error! MyClass.publicStaticMethod(); // NaN NaN 22 22
==== Public Access == Private methods are possible as inline constructor functions: function MyClass() { // The constructor var privateVariable= 10; // A private instance variable var privMeth1= function {...} // A private method fuction privMeth2 {...} // private method (shortcut) var that= this; // To make this available for priv methods } Notes: * Private methods possibly cause overhead, compared to the prototype way of public methods * ''this'' seems only to be accessible in private methods by the ''that'' workaround variable above * Public methods defined with the (recommended) ''prototype''-way doesn't seem to have access to private mehtods. You need privileged methods (see above) for that. Sources & more information: * [[http://javascript.crockford.com/private.html|Private Members in JavaScript]] * [[http://phrogz.net/JS/Classes/OOPinJS.html|OOP in JS, Part 1 : Public/Private Variables and Methods]] ==== Inheritance == FIXME see JS Guide 1.5 and dynWidget.js ==== Misc == * [[http://dojotoolkit.org/book/dojo-book-0-4/part-3-dojo-programming-model/global-dojo-objects|Using objects to simulate a namespace]] ===== Constants == ''const'' is mentioned in the [[https://developer.mozilla.org/en/JavaScript/Guide/Values%2c_Variables%2c_and_Literals#Constants|Mozilla guide]] but dosen't work with Rhino version :?: and probabaly neither with IE ===== Events == For event handling see: [[https://developer.mozilla.org/en/DOM/element#Event_Handlers|Mozilla]] & [[http://de.selfhtml.org/javascript/sprache/eventhandler.htm|Selfhtml]] See also Dojo [[dojo#events]] ==== Get the Source of the Event ==== /** conchange event handler function */ function getNameAndValueOfInputField(event) { var name, value; if (event) { name = event.target.name; value = event.target.value; } else { // IE specific code. I hate it! name = window.event.srcElement.name; value = window.event.srcElement.value; } return {"name":name, "value":value}; } // set conchange event for input field: var input = document.getElementById("franz"): input.onchange = getNameAndValueOfInputField; Event handler for value input fields ===== Closures == From [[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Working_with_Closures|MDC]] ==== Principle == A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created. Consequently, you can use a closure anywhere that you might normally use an object with only a single method. Instead of function Statusbar(elementId) { /* class constructor */ this.target = document.getElementById(elementId); this.setText = function(text) { this.target.innerHTML= text; } } var statusbar = new Statusbar("statusbar"); statusbar.setText("some text"); you can use: function makeStatusTextSetter(elementId) { /* closure factory */ var target= document.getElementById(elementId); return function(text) { target.innerHTML= text; } } var setStatusText= makeStatusTextSetter("statusbar"); setStatusText("some text"); ==== Practical Usage == Imho mainly as callbacks for events:
...
function makeCopyFkt(inboxNode, outboxNode) { /* inner funct is a closure witch gets attached the environment (including passed arguments) of the outer function */ return function () { outboxNode.innerHTML= inboxNode.value; } } window.onload = function() { /* called when html is loaded completely */ var inboxNode = document.getElementById('inbox'); var outboxNode = document.getElementById('outbox'); var copyFkt= makeCopyFkt(inboxNode, outboxNode); inboxNode.onblur= copyFkt; }; ==== Using class member methods as event callbacks == Global functions, i.e. functions which are defined outside of a class can easily be used as event callbacks for DOM nodes, but what about class member methods? The following example will not work, because the callback function ''copy'' has no access to ''this'' at the time being called: function Copier(inboxNode, outboxNode) { this.inboxNode = inboxNode; this.outboxNode = outboxNode; this.copy = function () { this.outboxNode.innerHTML= this.inboxNode.value; } } window.onload = function() { /* called when html is loaded completely */ var inboxNode = document.getElementById('inbox'); var outboxNode = document.getElementById('outbox'); var copier= new Copier(inboxNode, outboxNode); inboxNode.onblur= copier.copy; }; But it works with the closure way: function Copier(inboxNode, outboxNode) { this.inboxNode = inboxNode; this.outboxNode = outboxNode; this.copy = function () { self.outboxNode.innerHTML= self.inboxNode.value; } var self= this; // reference to this is saved in environment for closures } Or even shorter: function Copier(inboxNode, outboxNode) { this.copy = function () { outboxNode.innerHTML= inboxNode.value; } } But the best solution is imho to leave the class clean and pass the DOM node not directly the member function but an additional (anonymous) wrapper function as closure. This works also with real (prototype) methods: function Copier(inboxNode, outboxNode) { this.inboxNode = inboxNode; this.outboxNode = outboxNode; } Copier.prototype.copy= function() {this.outboxNode.innerHTML= this.inboxNode.value;}; window.onload = function() { /* called when html is loaded completely */ var inboxNode = document.getElementById('inbox'); var outboxNode = document.getElementById('outbox'); var copier= new Copier(inboxNode, outboxNode); inboxNode.onblur= function() { copier.copy(); }; // <== "wrapper" closure }; :!: Take care if you want to initialize more than on DOM callback in a loop. For this a callback factory function is necessary. See [[https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Closures#Creating_closures_in_loops.3a_A_common_mistake|JavaScript Guide]] FIXME Check out [[https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Closures#Emulating_private_methods_with_closures|Emulating private methods with closures]] ===== Ajax == ==== Links == [[http://www-128.ibm.com/developerworks/web/library/wa-ajaxintro1.html|Basic principles]] from [[http://www.ibm.com/developerworks/views/web/libraryview.jsp?search_by=Mastering+Ajax|Mastering Ajax series]] at IBM developerWorks - [[http://www.twilightuniverse.com/projects/sack/|Simple AJAX Code-Kit]] - [[http://www.jibbering.com/2002/4/httprequest.html|Raw cross browser code]] ==== Sending JSON to Server == To convert any javscript value to a JSON string, use json2.js at [[http://www.json.org/js.html|json.org]] ==== Todo / Pending == * Check [[ibm>web/library/wa-aj-ajaxcomm/|Various client-server communication mechanisms in an Ajax-based web application]] * Comet allows a web server to push data to a browser. [[wp>Comet_(programming)|Wikpedia article]] Introduction: [[http://www.developer.com/java/ent/article.php/3756841|Pushing Data to the Browser with Comet]] Manual: [[http://www.webreference.com/programming/javascript/rg28/|Comet Programming: Using Ajax to Simulate Server Push]] ===== Cookies == Code for writing and reading cookies by javascript is available [[http://www.webreference.com/js/column8/functions.html|here]]. An example can be found in my [[becki:sources:plainGTD]] App. Note that cookies can be manipulated easier by server side scripting, eg [[php]] ===== Dojo Toolkit == See [[dojo]] ===== Using Javascript from the Command Line == See [[jrunscript]]