JavaScript • Original name: Mocha/LiveScript for Netscape Browsers – By Brendon Eich; Renamed JavaScript in 1995 – Agreement: Netscape to support Java; Sun allow name change • Versions – JavaScript: Copyright owned by Sun Microsystems, now Oracle – Jscript: Microsoft’s version, named to avoid trademark issues – JavaScript submitted by Netscape to the European Computer Manufacturers Association (ECMA) in 1996 for standardization, and ECMAScript was born – ActionScript created by MacroMedia for Flash. The current version is compliant with the EMAScript standard • Notes – JavaScript, JScript, ActionScript are supersets of ECMAScript – http://www.ecma-international.org/publications/standards/Ecma-262.htm JavaScript • Original design and purpose – – – – Add life to web pages (leading to the name, LiveScript) User Web-content interactivity HTML manipulation with the Document Object Model (DOM) Client-side interpreted scripting language living in a browser • Extended design and purpose – – – – – – Client side/server interaction using AJAX (Asynchronous Java and XML) calls JavaScript's use in PDF documents Enhance the user experience Desktop widgets (small application showing on the desktop) Mobile applications Server side scripting • Recent activity contributing to its popularity – – – – Libraries, frameworks, and improved efficiency Language enhancements (Device control, local storage) Powerful cross platform programming model Minimize the need for browser plugins Difficulties • Browser compatibility – – – – Test on many browsers to ensure that the application works Each browser renders the application differently Desktop browsers: Firefox, Explorer, Chrome, Opera, Safari, Konquerer Mobile Device Browsers: Some WebKit-based, others are derivatives of their desktop counterparts, and some are unique to a particular device – JavaScript code blocks everything that is happening in the browser, so performance is a serious issue • Compiling – – – – Java is interpreted, so there is no actual compiler An Eclipse plug-in displays errors, sometimes incorrectly There are “lint” utilities available, with ideosyncrocies (i++) Browser utilities: Most browsers support console.log with a show console option that also displays run-time syntactical errors. Debugging JavaScript • Debugging – Desktop browsers have reasonable debuggers available – Mobile debuggers don’t always include debuggers • • • • • Firefox: firebug is a free downloadable plug in Explorer: The Developer tools option brings up a debugging window Chrome: Developer tools is an option under the tools option Opera: The inspect element option launches a debugging window Safari: Preferences/advanced must be first set to show the developer option in the options menu. After this, the start debugging option can be selected. Browser incompatibilities and lack of a universal API is one reason why developers cringe at the thought of JavaScript Using JavaScript in Web-pages • Within the page itself (preferably between the <head> and </head> tags <head><title>Some Page</title> <script type="text/javascript"> /* Code here */ </script> • In an external text file <head><title>Some Page</title> <script type="text/javascript" src="foo.js"></script> • Within an HTML tag <body onload="callSomeFunction();"> Note: JavaScript compression utilities remove all whitespace, rename variables and obfuscate the code. Resulting files are much smaller. Progressive Enhancement • Web-based application sections 1. Structure (HTML) 2. Presentation (CSS) 3. Behavior (JavaScript) • Goals: – Keep the three layers completely separate – Graceful degradation: Users can have JavaScript turned off and some browsers might not support the latest standards – Focus on content – Optimize the user experience regardless of the client platform Obtrusive JavaScript: that which lives in a web-page JavaScript is not Java JavaScript • Interpreted • Prototype-based • Object-based • Functions and Methods • First class functions • Loose dynamic typing • Function oriented scope • Special Purpose/embedded • Dynamic code Java • Compiled • Class based • Object-oriented • Methods only • Methods distinct from data • Strong static typing • Block oriented scope • General purpose/independent • Static code Just Like Java (JLJ) • If and switch statements (Java 1.7 allows switches on strings) • Basic loop syntax: while and do … while (…); Java: JavaScript: • • • • • • • • for (int i=0; i<10; i++) for (var i=0; i<10; i++) Reserved words: break, continue, return, this, new Identifier names: case sensitive, alphanumeric Comments: // and /* … */ Precedence/operators +=, -=, ++, --, *=, &&, ||, !, etc. Literals: 123, 1.23, 1.2E+3, 0x123, o777, "123" String concatenation using the + operator Escape sequences \t, \n, \b, \125, \xab Calls to functions and recursion JavaScript and Java Minor Differences • JavaScript optional end of line semi-colons (but recommended) • JavaScript: Dynamic evaluation of strings (ex: eval("var x=20");) • JavaScript automatically creates a variable that is not explicitly declared (bad practice because of inadvertent memory leaks). • JavaScript: console.log Java: System.out.println • JavaScript: Bitwise operations (&, |, ^, ~, <<,>>,>>>) force conversions (number to integer and back) are slow and not very useful • JavaScript: “undefined” for uninitialized variables, missing parameters and undeclared variables. “null” used by programmers to initialize a null object. • Double quotes and single quotes can enclose strings. • Java: final, JavaScript: const (not universally supported) • JavaScript: Numbers compare equal if same to sixteen digits of precision. • JavaScript: with(object) to access properties/methods without dot notation Instanceof vs typeof • Java: Reference variables are objects, so we use instanceof to test if one object is an instance of another • Javascript: The difference between objects and primitives are blurred Types: Undefined, Null, Boolean, Number, Object, string, and function o Typeof returns the string representation of an object’s type “undefined”, "object", "boolean", "number", "object", "string", "function" o Instanceof returns true if two objects are the same type • To test if a variable contains a string o typeof new String("ab") /* object */ new String("ab") instanceof String /* true */ o typeof "abc" /* "string" */ "abc" instanceof String /* false */ o Correct comparison: if (typeof str == 'string' || str instanceof String) Types • Java – Strongly typed: Only the declared type can be stored – Primitive types: • int, long, short, double, float, boolean, char, byte, etc. • Example: int x = 10; – Reference types: String, and all classes • JavaScript – Loosely typed: The last thing stored wins – Primitive types • number, boolean, function, string, etc. • var x = 10; – Reference types: arrays, all objects, etc. – Automatic conversions between types are common • Java: Block level Scope – A new scope starts with each opening brace • JavaScript: Functional Scope Scope // Works in JavaScript function doIt() { var sum = 0; for (var i=0;i<10;i++) { sum += i; } for (i=0;i<10;i++) { sum += i; } if (sum > 10) { var z = 3; } alert(sum+" "+i+" "+z); } doIt(); – Global Variables: Those declared without var or outside of all functions – Local variables: Declared with var in a function – JavaScript allows functions within functions. Local variables then live beyond execution (closure), and are accessible by the subfunctions (lexical scope) – Scope can be dynamic in that listener methods within an outer function cannot access its variables. – References to declared variables can be deleted: var x; delete x; – Variable declarations are hoisted in JavaScript – Local scope is the function where declared this: the local environment existing when a function is called Built-in Objects No huge class library, like Java’s • • • • • • • • Number: Contains various formatting methods Date: Many methods for time and date Math: Various methods for common calculations String: Many methods to manipulate strings Array: A variety of methods for manipulating arrays RegExp: search or test against regular expressions DOM based objects: described in the next set of slides Device: Part of the HTML 5 specification JavaScript global functions 1. 2. 3. 4. Not contained in any Object parseInt(), parseFloat() isNaN(), isFinite() eval() deCodeURI(), enCodeURI() Purpose: Replace special characters except: ":", "/", ";", and "?" with %xx, where xx is the corresponding hexadecimal number var uri="my test.asp?name=ståle&car=saab"; document.write(encodeURI(uri)+ "<br />"); Output: my%20test.asp?name=st%C3%A5le&car=saab 5. escape(), unescape() Purpose: Spaces, punctuation, accented characters, and any other nonASCII characters are replaced with %xx encoding, where xx is the corresponding hexadecimal number. Not good for URI encoding. document.write(escape("Need tips? Visit W3Schools!")); Output: Need%20tips%3F%20Visit%20W3Schools%21 Best Practice Bad var data; function test() { console.log(data); var data = 4; console.log(data); } /* The first console.log outputs ‘undefined’ because the local declaration is “hoisted” (but without the initialization) to the top of the function */ Better var data; Function test() { var data = 4; console.log(data); } /* Best practice is to declare all variables at the top of a function */ Conversions in JavaScript • Use of Wrapper objects var num1 = prompt("Enter number: "); var num2 = prompt("Enter number: "); var result = Number(num1)+Number(num2); alert("Result = " + result); Boolean of 0, -0, "", var myString = String(result); false, NaN, undefined, alert( myString + " " + Boolean(result)); null evaluates to false • Using parse methods var number = parseInt(num1,10); number = parseFloat(num1); Boolean of anything else evaluates to true Note: parseInt and parseFloat convert to the first non digit, Number() does not; it returns NaN if the conversion fails Strict Comparisons (=== and !==) 0==false ; // true 0===false; // false, they are different types 1=="1" // true, auto type coercion 1==="1" // false, because different types 1<"3" // true, auto type coercion NaN==NaN // false, An object that is not equal to itself NaN===NaN // false, An object that is not equal to itself isNaN(NaN); // true new Number(3)==new Number(3) // false, not the same object new Number(3)===new Number(3) // false, not the same object new Number(3).valueOf()==new Number(3).valueOf() // true Recommendation: Use === and !==; not == and != Arrays are not Arrays in the Java Sense They are also stacks, queues, deques, arraylists, hash tables Each element can be any type • Declaration: var data=[]; or var data=new Array(10); or var data=[1,2,3]; • Manipulate an array Note: Initializer lists for array indices are enclosed with square brackets – Add/Remove to/from end: data.push("a", "b", "c"); or x = data.pop(); – Add/remove to/from front: data.unshift("a", "b”); or x = data.shift(); – Add/Remove/Replace n elements from index x and return removed elements data.splice(x,0,"a"); or data.splice(x,n); or data.splice(x,2, "a","b"); – Add/Remove associative (hash) elements : data["age“]=25; (equivalently, data.age=25;) – Extract part of an array: data.slice(start, end); // start -> end (not including) – Merging arrays: data.concat(firstData, secondData, … , lastData); – Merging elements: data.join(";") or data.toString() Note: Other JavaScript Array methods (ex: sort()) exist For/In loop <html><body><script type="text/javascript"> var person={First:"John", Last:"Doe", Age:25}; String key = "Middle“; var x; for (x in person) { if(person[x]===key) console.log(person.Last + " " + key); } </script></body></html> Note: First, Last, Age are properties of person, a polymorphic object (this one lacks Middle) Warning: For/In loops are very slow, so use with care Polymorphic Data Structures • Returning a rectangle data structure – JavaScript: return { x:10, y:20, width:800, height:400 }; – Java: return new Rectangle( 10, 20, 800, 400 ); • Returning a dimension data structure – JavaScript: return { width:800, height:400 }; – Java: return new Dimension( 800,400 ); • Polymorphic processing in JavaScript var rectOrDim = getRectorDimensionFromFunction(); if (rectOrDim.x) { /* Process as a rectangle */ } else { /* Process as a Dimension */ } Polymorphic object: one where all of its properties are not required JavaScript labels • JavaScript instructions labeled for later reference • Example endLoop: for (i=0; i<10; i = i + 1) // Note: JS Lint doesn’t like ++ or – { for (j=0; j<10; j = j + 1) { for (k=0; k<10; k = k + 1) if ( i * j * k === someVariable) break endLoop; } } Note: the continue statement goes to the next outer loop This works in Java, but the language does not guarantee it. Generally, its use is not best practice. (Classic CS paper by Dijkstra: “Goto considered harmful”) User Interface • Java: AWT or SWING, JavaFX, JOptionPane • JavaScript: alert, prompt, confirm. Good for debugging, not recommended for production (blocks the browser). • JavaScript: Utilize HTML widgets • JavaScript: Directly write HTML to the web page – document.write("<h3>Some header</h3>"); – element.innerHTML("<h3>With new line</h3>"); – Framework libraries, like jQuery or Dojo • Document Manipulation: See next week’s slides Functions • Functions can simulate classes, define embedded properties and methods, and instantiated with the new directive • Signature lines o No return type declared o List parameters without any types • private and public o o o o var x = 10; within a function is private this.x = 10; within a function is public this.doSomething = function() { /* … */ } is a public function var doSomething = function() {/* … */ } is a private function • Functions can be passed to functions as arguments and functions can be returned from functions First class functions: functions that are treated as a data object Creating an Anonymous Function Definition: Function without a name (function () { "use strict"; // Strict syntax verification var family = ["bill", "joe", "mary"], var num = family.length, var data = ""; var i; // Note all variables declared on top for (i=0; i<num; i++) // Use num, not family.length data += "<p>" + family[i] + "</p>"; return data; })(); // This syntax creates and executes the anonymous function Purpose: Pass as a function argument Purpose: Encapsulate variables to avoid memory leaks Anonymous Callback Function Callback function: passed as an argument and called when an event occurs window.addEventListener("load", function (event) // Function with an argument (undefined if not there) { "use strict"; // Strict syntax verification (ex: no undeclared variables) event.preventDefault(); // Prevent browser default behavior var element = document.getElementsByTagName("article")[0]; var family = ["bill", "joe", "mary"], num = family.length, data = ""; var i; // Note: all variables are declared on top (no hoisting) for (i=0; i<num; i++) // Use num, not family.length (much faster) data += "<p>" + family[i] + "</p>"; Browser default behavior • Navigate on link click element.innerHTML = data; • Right click: context menu }, false); • Cause a form submission • Jumps to other pages Note: InnerHTML does not actually create DOM elements for the tags Creating a method in a data object var persons = [ { first: "John", last : "Doe", id: 5566, full: function() {return this.first + " " + this.last);} , { first: "Bill", last: "Miller"} ]; persons[0].full(); or persons[0]["full"](); Note: persons is an array whose first element contains a method JSON (Javascript object notation) Note: Theoretically, you would also var data = ' { "contacts" : be able to declare functions in [ { "name": "john", JSON. However, JSON is only for "email": "john@bla.bla", text-based data exchange, so it is not allowed (major security hole). }, Note: A string containing text{ "name": "pete", based JSON can be turned into a "email": "pete@bla.bla", standard JavaScript object with: JSON.parse(text); }, Note: JSON is rapidly becoming more popular than XML for Web] services; it is lightweight, smaller, } '; and easier to process data = JSON.parse(data); Note: JSON.stringify(object) converts from object to string alert(data.contacts[0].name); or alert(data["contacts"][0]["name"]); John outputs Nested JSON Example var data = '{ "id": "0001", "type": "donut", "name": "Cake", "ppu": 0.55, "batters": { "batter": [ { "id": "1001", "type": "Regular" }, { "id": "1002", "type": "Chocolate" }, { "id": "1003", "type": "Blueberry" }, ] }, "topping": [ { "id": "5001", "type": "None" }, { "id": "5002", "type": "Glazed" }, { "id": "5005", "type": "Sugar" }, { "id": "5004", "type": "Maple" } ] }' data = JSON.parse(data); console.log(data.batters.batter[1].type); Outputs Chocolate Creating a simple function function showNames() { "use strict"; // Strict syntax verification var family = ["bill", "joe", "mary"], var num = family.length, var data = ""; var i; // Note all variables declared on top for (i=0; i<num; i++) // Use num, not family.length data += "<p>" + family[i] + "</p>"; return data; } Anonymous Function Returned Functions declared as variables and called without their name function paint(type, color) { var str = "The"+type+" is"+ color; var tellMe = function() { document.write(str+".<br> "); } return tellMe; } var say1 = paint("rose", "red"); var say2 = paint("sun", "yellow"); say1(); say2(); Note: The variable, str, still exists after the call to paint Completes because it is needed by subsequent calls to the anonymous function Closure: a function that remembers the environment in which it was created. Output: function () { document.write(str + "."); } The rose is red. The sun is yellow. Closure-based object creation Goal: Define StringBuffer class for fast concatenation (like in Java) Advantage: Looks more like Java with private/public instance variables and method <html<body><script type="text/javascript"> StringBuffer = function() // Siulated Class declaration { var buffer = []; // Private variable this.append = function(s) {buffer.push(s);} this.toString = function() { return buffer.join("");}; } var buffer = new StringBuffer(); Output: Happy Day! buffer.append("Happy "); buffer.append("Day!"); document.write("<h3>" + buffer.toString() + "</h3>"); </script></body></html> Prototypes, not Classes Java is class-based; JavaScript is a Prototype-based • There are no classes present. Prototype objects are enhanced dynamically at run-time • JavaScript prototypes are of polymorphic associative arrays of functions and properties var object = { x:10, doIT: function() { /** some code **/} or var object = []; object["x"] = 10; object["doIt"] = function() { … }; alert(object.x); or alert(object.doIt()); • Inheritance: achieved by adding constructors to existing objects • Augmented objects serve as prototypes for even newer objects. Prototype-based properties Output: 1 Value = 1 undefined var MyClass = function(){}; var my = new MyClass(); // Create an instance MyClass.x = 2; // Add a property to future objects MyClass.prototype.y = 1; // Add a prototype property // Add a toString() prototype method MyClass.prototype.toString = function() { return "Value="+this.x + " " + this.y; } document.writeln(my.toString()); Note: Every object in JavaScript has a prototype object; adding to it affects all instances, even those previously instantiated JavaScript Prototype Chain Allows object inheritance Caution: Inheritance leads to significant runtime slowdowns • All JavaScript objects have a prototype object. JavaScript will attempt to find a property in an object first. If it is not there, JavaScript then refers to the object’s prototype, and so on through sub-objects in the prototype object. • Prototype inheritance chains can nest without limit. In general, chains should be short. Long chains lead to bad performance JavaScript Inheritance Cat Twigs says Meow Dog Spot says Woof function Pet(name) // Base class { this.name = name; this.who = function() { return name; } } Pet.prototype = { species: 'animal', sleep: function() { return name + ' zzzz'; } } function Cat(name) { Pet.apply(this, arguments); } // Derived class constructor Cat.prototype = Object.create(Pet.prototype); // Set prototype base class (Pet) Cat.prototype.constructor = Cat; // Designate constructor; not Pet Cat.prototype.speak = function() { return "Meow"; } // Extension function function Dog(name) { Pet.apply(this, arguments); } // Derived class constructor Dog.prototype = Object.create(Pet.prototype); Note: The latest ECMA Dog.prototype.constructor = Dog; standard has class and Dog.prototype.speak = function() { return "Woof"; } extends reserved words // Example using inheritance var cat = new Cat("Twigs"), dog = new Dog("Spot"); document.write("<h3>Cat "+cat.sleep()+"</h3>"); document.write("<h3>Dog " + dog.who() + " says " + dog.speak()) + "</h3>"; Add String Class trim() Methods <html><head><title>Add Trim()</title></head> <body><script type="text/javascript"> String.prototype.ltrim = function() { return this.replace(/^\s+/,''); } String.prototype.rtrim = function() { return this.replace(/\s+$/,''); } String.prototype.trim = function() { return this.ltrim().rtrim(); } var text = " abc ", text2 = " def ".trim(); document.write("<h3>"+text.trim()+text2+"</h3>"); </script></body></html> JavaScript is more lightweight than Java Programmers add functionality; Applications do not have unneeded features Note: Any JavaScript core object, (like Array, Date, Math, Number, RegExp) can be extended with new properties and methods Regular Expression Review In JavaScript: / pattern / Used by String match and replace methods 1. 2. 3. 4. 5. 6. 7. 8. 9. ^ - beginning of string, $ - end of string \s , \d, \w – white space, digit, word (identifier) respectively \S, \D, \W – Not white space, digit, word respectively [abcde] or [a-e] – any of the characters a through e . (period) matches any character abc|def match abc or def \n, \r, \t – new line, carraige return, tab respectively * - zero or more times, + - one or more time, ? – zero or one time {3,6} – three through six times, {,4} – up to four times Regular Expression Examples var data = "(322)- abc-4568" 1. Remove all spaces and dashes var reg=/[ -]+/g; out = data.replace(reg, ""); 2. Remove all parentheses, spaces, dashes var reg = new RegExp("/[() -]+/g"); out = data.replace(reg, ""); 3. Remove non-digits: out = data.remove(/\D/g, ""); 4. Remove non-alphabetic characters from front data.remove(/^\W/, ""); or data.remove( /^[0-9a-zA-Z]+/, ""); 5. Phone number: first remove white space, parens, & dashes var reg = /^\d{3}([A-Za-z0-9]{7}$/; if (data.match(reg) === true) console.log("okay"); Overloading Functions Not the way that Java does it function Test(a, b) { if (b) {/* or if (b!==undefined), do something */} else { var t = typeof(a); // Get type of first argument switch (t) // Execute code based on the type { case "number" : /* Number Stuff */ break; case "string" : /* String Stuff */ break; case "boolean" : /* Boolean Stuff */ break; case "object" : /* Object Stuff */ break; default: alert("No overload for type: " + t); } } } Variable Number of Arguments function AddNumbers() { var sum = 0; for(var i=0; i<arguments.length; i++) { sum += arguments[i]; } return sum; } Use the arguments object Browser Detection Browser specific code sometimes needed for cross-platform compatibility • Check user agent: "android", "ipod", "iphone", "chrome", "opera", "firefox", "safari" function isAndroid() { var browser = navigator.userAgent; return browser.toLowerCase().indexOf("android")>=0; } • Check appName for Explorer: (different than all other browsers) this.isExplorer = function() { var browser = navigator.appName; return browser.toLowerCase().indexOf("microsoft")>=0; } Functionality Detection Browsers don’t support all of the audio codecs var audio = []; audio["mp3"] = false; audio["ogg"] = false; audio["wav"] = false; try { var test = document.createElement('audio'); audio["bgsound"] = this.isExplorer(); // Currently canPlayType(type) returns: "", "maybe" or "probably" audio["mp3"] = test.canPlayType && test.canPlayType('audio/mpeg') != ""; audio["ogg"] = test.canPlayType && test.canPlayType(' audio/ogg; codecs="vorbis" ') != ""; audio["wav"] = test.canPlayType && test.canPlayType('audio/wav‘!=""); } catch(e) { } if (!audio["ogg"]) // Doesn’t handle OGG Try Catch to Detect Functionality try { lesson = new Lesson(type, lessons[num]); } catch (e) { showMessage(e.name+" "+e.message+" "+ e.toString()+" " + e.stacktrace); } Note: Throw clause in JavaScript • Note: throw( /*some string, integer, boolean, or object */) • Example: throw ("Lesson "+type+" not supported\n"+e.stack); JavaScript Security Policy • Sandbox: – JavaScript can only perform web-related actions, they cannot create files or access the client’s file system. There are, however, tentative plans to relax this somewhat. – There is the ability to use a local storage facility provided by HTML5 for persisting name/value pairs. Older cookie based save/load is also possible. • Same Origin Policy: – scripts from one web site cannot access usernames, passwords, or cookies sent to another site or created by a script from another web site Security Vulnerabilities • Poorly designed JavaScript code: Secret information embedded in JavaScript cannot be hidden from attackers. • Browser and plug-in coding errors: Exposes flaws, such as buffer overflow or enabling access to client side facilities • JavaScript hijacking: Exploits a page that returns private unencrypted information in JSON or XML formats. • Cross-site-scripting (XSS): malicious script that alters web pages. The victim may then disclose privileged information • Cross-site request forgery vulnerability (CSRF): Attacker code tricks the victim's browser into taking unintended actions