JavaScript The Good and The Bad. Caveat We are not studying JavaScript so that you can write better...
-
Upload
abel-bennett -
Category
Documents
-
view
223 -
download
1
Transcript of JavaScript The Good and The Bad. Caveat We are not studying JavaScript so that you can write better...
Caveat• We are not studying JavaScript so that you can write better
scripts for your web pages (although if you’ve done some JavaScript in the past, the info here may help you understand more about what’s really happening)
• We will not cover the DOM or many techniques used in web pages
• We will take a look at some of the more interesting aspects of JavaScript from a programming language design perspective
• Info from this lecture will be included on the next exam
Language Design • An object “encapsulates” data and methods• Assume you want to create a new language that contains
objects• You want to keep it simple• How can you create something that’s quick and easy to
implement?
Data Types and Objects• Primitive types are numbers, strings, boolean, null and undefined• Everything else is an object• An object is simply a mutable, keyed collection• There are no classes!
var my_cat = {name: "Geronimo", // no quote if legal
name"coat-color": "orange" // coat_color legal
};document.writeln(my_cat.name);document.writeln(my_cat["coat-color"]);document.writeln(my_cat["color"]);//document.writeln(my_cat.coat-color);
More on objects• Can add a property by assigning a valuemy_cat.age = 3;document.writeln(my_cat.age);
• Objects are passed by reference• Object keys are all strings
Prototypes• In addition to the key/value properties, each object has a pointer
to the object’s prototypedocument.writeln(Object.getPrototypeOf(my_cat));
• If not set explicitly, this will be [object Object] • Prototype link is used only in retrieval
Prototypes – simple example• Wordy version (new syntax)• Object.create(proto[, propertiesObject])
var cat = Object.create(null);Object.defineProperty(cat, 'sound',
{value: "meow", writeable: true });
// can also set enumerable and configurablevar stray_cat = Object.create(cat);Object.defineProperty(stray_cat, 'name',
{value: "Sigfried", writeable: true});stray_cat['coat-color'] = "tuxedo";document.writeln(stray_cat['name']);document.writeln(stray_cat['coat-color']);document.writeln(stray_cat['sound']);
Prototypes, continued
Example from: http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/
common to override toString
The process of using the chain of prototypes to retrieve properties is known as delegation. If the property is not on the chain, the result is undefined.
Augmenting the basic types
Number.prototype.integer = function(){ return Math[this < 0 ? 'ceil':'floor'](this); }
document.writeln(10/3);document.writeln((-10 / 3).integer()); document.writeln((10 / 3).integer());
• How does this compare to Ruby?
See: http://stackoverflow.com/questions/6868883/augmenting-types-in-javascript
Augmenting Object
o1 = {x: 2}; Object.prototype.doSomething = function() {
document.writeln("Just do it!"); }o1.doSomething();o2 = {y: 3};o2.doSomething();
How do you accomplish this in other languages?Think about: features to add behavior, vs features to organize behavior
Namespace• JavaScript issue: there’s a tendency to use global variables to
contain all the data for an app. Clearly this can lead to reliability and maintainability issues.
• A namespace is a container which allows developers to bundle up all functionality under a unique, application-specific name. In JavaScript a namespace is just another object containing methods, properties and objects.
• Some guidelines (beyond our scope, really):• Place the namespace declaration in its own file• That file can be included in all app files (e.g., XUL)• Link has some guidelines for naming convention
• For this course, interesting aspect is how JS handles namespace compared to other languages.
https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/JavaScript_Object_Management
Functions – Powerful Stuff!• Functions are objects• Include two additional hidden properties: context and code
Object.prototype { name: value name2: value2 fnName: function}
hidden
Function.prototype
Object
{ name: value name2: value2 }contextcode
Objecthidden
First-class objects• Can be stored in variables, objects and arrays• Can be passed as arguments to functions• Can be returned from functions• Can have methods• Special property: they can be invoked
var add = function(a, b) { return a + b;}document.writeln(add(5,6));document.writeln(add(5,6,7));
Function invocation• Invocation operator is ()• Parameters inside (), separated by commas• May have more values than parameters (just ignored)• May have more parameters than values (set to undefined)• No type checking• Two additional parameters, this and arguments• Four different invocation patterns:• Method invocation – similar to instance method• Function invocation• Constructor invocation • Apply invocation
• Differ in how this is initialized
from JavaScript: The Good Parts
Method invocation• Function can be stored as property of an object• this will be bound to the calling object
var myObject = { value: 0, increment: function(inc) {
this.value += typeof inc === 'number' ? inc : 1;
}};myObject.increment();document.writeln(myObject.value);myObject.increment(3);document.writeln(myObject.value);
Function invocation• this is bound to global object• causes issues with inner functions (covered later)
Constructor invocation• Functions intended to be used with new prefix are called
constructors• The new prefix causes an object to be created with a hidden
link to the function’s prototype method, and this is bound to the new object
• This syntax is typically used with classes… but JavaScript has prototypes. Just caused confusion (not recommended, and JavaScript 1.8.5 has Object.create syntax)
• NOTE: Why cover this, if it’s not recommended? Because it’s good to think about mistakes that have been made in language design. Also, lots of old examples online… in many languages.
Constructor examplevar Quo = function(string) {
this.status = string; // implicit return value is this};// Must have prototype, otherwise not shared with // new object. Quo.prototype.get_status = function() {
return this.status;};// Quo is a function object// Putting new in front of it causes a new // object to be created – weird!var myQuo = new Quo("confused");document.writeln(myQuo.get_status());
Apply invocation functionfunction sum() { var result = 0; // note the use of the arguments array for (var i = 0; i < arguments.length; i++) { result += arguments[i]; } return result; } var args = [1,2,3];// first argument to apply is the context// in other words, this// second is an arraysum.apply(null, args); // will return 6
From: http://stackoverflow.com/questions/1976015/how-to-implement-apply-pattern-in-javascript
Apply invocation with context
var obj = { data:'Hello World'
} var displayData = function() { document.writeln(this.data);
} displayData(); //undefined, no global data displayData.apply(obj); //Hello World// call is similar to apply, but it takes // an argument list rather than an arraydisplayData.call(obj); // empty arg list
From: http://doctrina.org/Javascript-Function-Invocation-Patterns.html
Another call/apply examplevar x, o1, o2, r1, r2, r3; x = 4; o1 = {x: 2}; o2 = {x: 7};
f = function(m, n) {return m * n * this.x;}; r1 = f(3, 1); r2 = f.call(o1,3, 1); r3 = f.apply(o2,[3, 1]); document.writeln(r1);document.writeln(r2);document.writeln(r3);
From: http://javascript.about.com/od/byexample/a/objectoriented-call-apply-example.htm
Usage brainstorm• How/when might we use apply and/or call?
// Say a greeting to any object with a namesay_hello = function() { return "Hello " + this.name; }// Add random health to any object with healthinc_health = function() { this.health = Math.floor((Math.random() * 100) + 1); }// Assumes o1 already exists as an objecto1.name = "Cyndi";o1.health = 5;document.writeln(say_hello.call(o1));inc_health.call(o1);document.writeln(o1.health);
Quick Discussion: How does this compare to Ruby?
Scope• Most C-inspired languages have block scope• JavaScript has blocks… but not block scope (function scope)
var foo = function() {var a=3, b=5;var bar = function() { var b=7, c=11; a += b + c; document.writeln("a: "+a+" b: "+b+" c: " +
c);}bar();document.writeln("a: " + a + " b: " + b);
}foo();
Info: Crockford + http://stackoverflow.com/questions/17311693/why-does-javascript-not-have-block-scope
Scope example
C# doesn’t compile
public void TestScope() { if (true) { int i = 5; } i.ShouldEqual(5); // does not compile }
JavaScript
var foo = function() { // this is recommended: // var a; if (true) { // but this works var a = 5; } alert(a); } foo();
From: http://lostechies.com/jimmybogard/2008/09/26/javascript-block-scoping/
Inner functions
• Inner functions get access to the parameters and variables of the functions they are defined within • except this and arguments• Issues!!
Inner functions examplevar add = function(a, b) { return a + b;}var anObject = { value: 4,};// this not set properlyanObject.doubleIt = function() { var helper = function() { this.value = add(this.value, this.value); }; helper();};document.writeln("before doubleIt");document.writeln(anObject.value);anObject.doubleIt(); document.writeln("after doubleIt");document.writeln(anObject.value);
// common workaroundanObject.double = function() { var that = this; var helper = function() { that.value = add(that.value, that.value); }; helper();};document.writeln("before double");document.writeln(anObject.value);anObject.double(); document.writeln("after double");document.writeln(anObject.value);
Inner function - workaroundanObject.double = function() {
var that = this;var helper = function() {
that.value = add(that.value, that.value);
};
helper();};
Sidebar: first-class functions
// avoid repeated code on previous slideanObject.someFn = function(func) {
document.writeln("before fn value");document.writeln(anObject.value);func.call(this); document.writeln("after fn value");document.writeln(anObject.value);
};// passing the function as an argumentanObject.someFn(anObject.doubleIt);anObject.someFn(anObject.double);
Closures*var quo2 = function(status) { // returning an object with get_status method return {
// even after quo2 ends, will have access to // copy of parameter, via the context get_status: function() {
return status;}
};};var myQuo = quo2("amazed");document.writeln(myQuo.get_status());myQuo.status = "dazed";document.writeln(myQuo.get_status());
Examples from JavaScript: The Good Parts
*brief intro, you’ll explore in homework
Another closure examplevar fade = function (node) { var level = 1; var step = function() { var hex = level.toString(16);
node.style.backgroundColor = '#FFFF' + hex + hex;if (level < 15) { level += 1; setTimeout(step, 100);}
}; // will call step after 100 milliseconds (1/10th sec) // fade already returned, but its variables (e.g., level) // live on inside this closure. setTimeout(step, 100); }; fade(document.body);
Final closure example
var addScore = (function(points) {var score = 0;return function (points) {
return score+=points; }})()
document.writeln(addScore(5));document.writeln(addScore(7));
• Idea: if points stored in global var, anything could change. This way, score is protected in a closure.
Relatedvar scoreChanger = (function(points){ var score = 0; var operation = {
add: function(points) {return score += points;},sub: function(points) {return score -= points;},mult: function(points) {return score *= points;},div: function(points) {return score /= points;}}return operation;})()
scoreChanger.add(1);document.writeln(scoreChanger.add(2));document.writeln(scoreChanger.mult(5));
Callbacks• Another use for functions, dealing with asynchronous events• Naïve way to make a server request (freeze til get response):
request = prepare_the_request();response = send_request_synchronously(request);display(response);
• A better approachrequest = prepare_the_request();send_request_asynchronously(request, function(response) { display(response);});
Again, passing a function as an argument
Memoization• Remembering the results of previous operations, so as to
avoid unnecessary workcall_count = 0;var fibonacci = function(n) {
call_count += 1;return n < 2 ? n : fibonacci(n-1) +
fibonacci(n-2);};document.writeln("\nNAIVE FIBONACCI");for (var i=0; i<=10; i += 1) {
document.writeln('// ' + i + ':' + fibonacci(i));}
document.writeln("count of calls: " + call_count);
Cool example from JavaScript: The Good Parts
Memoized Fibonaccivar fib_count = 0;var fibonacci2 = function() { var memo = [0,1]; var fib = function(n) { fib_count += 1; var result = memo[n]; if (typeof result != 'number') { result = fib(n-1) + fib(n-2); memo[n] = result; } return result; }; return fib;}();
for (var i=0; i<=10; i += 1) { document.writeln('// ' + i + ':' +
fibonacci2(i));}document.writeln("count of calls: "
+ fib_count);
• fib_count is 29• 11 calls in for loop• only 18 to calculate values
General purpose memoizervar memoizer = function (memo, fundamental) { var shell = function(n) { var result = memo[n];
if (typeof result != 'number') { result = fundamental(shell, n); memo[n] = result;}return result;
}; return shell;};
var fibonacci3 = memoizer([0,1], function(shell, n) { return shell(n-1) + shell(n-2);});document.writeln("Fibonacci 10: " + fibonacci3(10));
var factorial = memoizer([1,1], function(shell, n) { return n * shell(n-1);});document.writeln("Factorial 5: " + factorial(5));
Object-based vs Object-oriented
• http://en.wikipedia.org/wiki/Object-based_language• http://stackoverflow.com/questions/15430004/core-
difference-between-object-oriented-and-object-based-language• http://cse3342.blogspot.com/2006/03/object-based-
vs-object-oriented-and.html