This is the content for a presentation on JavaScript. I just made the content publicly available for interested people who attended the session. Most of the slides are very informative though so that anyone could make use of hopefully.
I'll be visiting the content and adding more clarification soon.
The Name: JavaScript
-
Prefix: Java
Is it related to Java? A subset maybe?
No
It has nothing to do with Java
-
Suffix: Script
Is it just a scripting language?
Not a real programming language?
No
It is a complete programming language
Popularity
Available in all browsers
The most popular programming language
The Most Misunderstood Programming Language
The name
prefix and suffix
It is different
Programmers don't even bother to learn it
Unfairly blamed for the awfulness of the DOM
Previous bad implementations
Lack of good books
Design: Very Good Ideas
Functions are first class objects
They can be passed as arguments and return values
Loose Typing
Easier - more expressive
Dynamic Objects
General containers = hash tables
Object Literal Notation
Very expressive
Design: Controversial Ideas
Prototypal Inheritance
No Classes
Objects inherit directly form other objects
Very powerful
Not commonly understood very well
Design: Very Bad Ideas
Linkage through global variables
Compilation units (scipt tags) are combined in a commmon global namespace
Variables can collide
Types (Values)
Simple types
Numbers
Strings
Booleans
null
undefined
Objects
Numbers
Only one number type
64-bit floating point (same as Java's double)
0.1 + 0.2 // 0.30000000000000004
100, 100.0, 1e2 are equivalent
NaN and Infinity are special numbers
Numbers: NaN
Special Number: Not a Number
Result of erroneous operations
2 * 'a' // NaN
Toxic
5 + NaN // NaN
Not equal to any value (including itself)
NaN == NaN // false isNaN(NaN) // true
Numbers: Infinity
Special Number
1 / 0 // Infinity 1 / Infinity // 0
Represents numbers >
1.79769313486231570e+308
1.8e308 // Infinity
Numbers: Number function
Converts a value into a number
Number('') // 0 Number('0032') // 32 Number('123abc') // NaN Number('abc') // NaN
So does the '+' prefix operator
+'' // 0 +'0032' // 32 +'123abc' // NaN +'abc' // NaN
Numbers: parseInt
Also converts a value into a number
Stops at first non-digit character
parseInt('123abc', 10) // 123
If no radix is passed it defaults to 10 (8 if input starts with 0)
parseInt('32') // 32 (as decimal) parseInt('0032') // 26 (as octal if starts with 0)
Always specify the radix
parseInt('0032', 10) // 32 parseInt('0032', 8) // 26
Numbers: Math
An object containing methods that act on numbers
abs, acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random, round, sin, sqrt, tan
Math.floor(12.53) // 12
Also contains some useful constants
E, LN10, LN2, LOG10E, LOG2E, PI, SQRT1_2, SQRT2
Math.PI // 3.141592653589793
Strings
0 or more 16-bit characters
A character is just a String of length 1
Immutable
String literal
'abc' == "abc" // true
length property (number of 16-bit characters)
'abc'.length // 3
Strings
Concatenating
'Java' + 'Script' // 'JavaScript'
String function
String(123) // '123'
Strings have methods
'cat'.toUpperCase() // 'CAT'
Boolean
true - false
Boolean function
Boolean(truthy_value) // true
!! prefex operator
!! falsy_value // false
null
A value that is not anything
undefined
A value that is not even a value
The default value for variables and parameters
The value of missing members of an object
Falsy values
6 possible falsy values
!! false // false !! null // false !! undefined // false !! '' // false !! 0 // false !! NaN // false
All other values are truthy
!! '0' // true
Objects
An object is a container of properties
A property has a name (string) and value (any type)
Class-free (No constraints on names/values of new properties)
Objects are hash tables
Protype linkage
Arrays, functions, regular expressions and objects are objects
Objects: Object literal
Very convenient for creating new object values
A pair of curly braces surrounding 0+ name/value pairs
var empty_object = {};
var person = { 'first-name': 'John' };
var city = { name: 'Alexandria', location: { latitude: 31.2, longitude: 29.9 } };
Objects: Retrieval
Subscript notation
person['first-name'] // 'John' city['name'] // 'Alexandria'
Dot notation
city.name // 'Alexandria' city.location.latitude // 31.2
Missing properties
person.nickname // undefined
Objects: Retrieval
|| operator (set default values)
var name = person.nickname || 'anonymous'; // 'anonymous'
&& operator (handle missing nested objects)
city.country // undefined city.country.name // throws a TypeError city.country && city.country.name // undefined
Objects: Update
Simply by assignment
person['first-name'] = 'Thomas'; // Replaced 'first-name'
person['last-name'] = 'Anderson'; // Added 'last-name'
Objects: Reference
Objects are passed around by reference
var x = person; // x & person refer to the same object x.nickname = 'Neo'; person.nickname // 'Neo'
var a = {}, b = {}, c = {}; // different empty objects
var a = b = c = {}; // the same empty object
Objects: Prototype
Every object is linked to a prototype object
Objects created by object literal are linked to Object.prototype
Object.prototype.foo = 'bar'; var a = {}, b = {}; a.foo // 'bar' b.foo // 'bar'
Protype link is used only for retrieval (prototype chain)
a.foo = 'blah'; // Added foo property to a a.foo // 'blah' b.foo // 'bar'
Objects: Prototype
We can specify the prototype for a new object
Complex but simplified by
Object.create
function (in new JS editions)if (typeof Object.create != 'function') { Object.create = function(o) { var F = function F(){}; F.prototype = o; return new F(); }; } var p = {foo: 'bar'}; var a = Object.create(p); a.foo // 'bar'
Objects: Reflection
hasOwnProperty
Object.prototype.foo = 'bar'; var a = {foo: 'blah'}, b = {}; a.foo // 'blah' b.foo // 'bar' a.hasOwnProperty('foo') // true b.hasOwnProperty('foo') // false
Objects: Enumeration
for in
var someone = {'first-name': 'John', 'last-name': 'Doe'}; var person = Object.create(someone); person.profession = 'artist'; person.age = 30; for (p in person) { var mark = person.hasOwnProperty(p) ? ' ' : '* ' console.log(mark + p + ': ' + person[p]); } // profession: artist // age: 30 // * first-name: John // * last-name: Doe
Objects: Delete
delete
removes a property from an objectdelete person.age; person.age // undefined
May let a prototype property shine through
person['first-name'] = 'Jason'; person['first-name'] // 'Jason' delete person['first-name'] person['first-name'] // 'John'
Objects: Reducing Global Footprint
A single global variable for your application
var MyAPP = {};
Contains all your variables (as properties)
MyAPP.someone = {'first-name': 'John', 'last-name': 'Doe'}; MyApp.person = Object.create(MyAPP.someone);
Functions
The best thing in JavaScript
A function encloses a set of statements that execute when invoked
Functions are objects
Linked to a prototype (Function.prototype)
Can be stored in variables, objects, and arrays
Can be passed as arguments to functions and can be returned from functions
A function has a prototype property
Uses:
Code reuse, Information hiding, Composition
Functions: Function Literal
4 parts:
function (reserved word)
name (optional)
parameters
body
var add = function (a, b) { return a + b; };
Functions: Invocation
Extra parameters:
this
&arguments
Invocation Patterns
Method invocation pattern
Function invocation pattern
Constructor invocation pattern
Apply invocation pattern
Arguments
No error if not matching number of parameters
Extra arguments are ignored
Missing will be
undefined
Functions: Method Invocation Pattern
Function is stored as a property of an object
this
will be the objectvar myObject = { value: 0, increment: function (inc) { this.value += inc; } }; myObject.increment(2); myObject.value; // 3
Functions: Function Invocation Pattern
Function is not a property of an object
this
will be the global object (design mistake)myObject.double = function () { var that = this; // Workaround. var helper = function () { that.value = 2 * that.value }; helper(); // Invoke helper as a function. }; myObject.double(); // Invoke double as a method. myObject.getValue(); // 4
Functions: Constructor Invocation Pattern
Invoked with
new
prefixA new object is created & linked to function's prototype property
this
is bound to the new objectvar Car = function (speed) { this.speed = speed; }; Car.prototype.move = function() { return 'moving at ' + this.speed; }; var my_car = new Car('40 k/h'); my_car.move(); // moving at 40 k/h
Functions: Apply Invocation Pattern
apply
is a method of functions2 parameters: value for
this
& array of argumentsvar util = { get_status: function(uppercase){ return uppercase ? this.status.toUpperCase() : this.status; } }; var obj = { status: 'ok' }; util.get_status.apply(obj, [true]); // 'OK'
Functions: Arguments
arguments
: array of parameters passed to a functionarray-like object
var sum = function () { var i, s = 0; for (i = 0; i < arguments.length; i += 1) { s += arguments[i]; } return s; }; sum(4, 8, 15, 16, 23, 42) // 108
Functions: Return
Functions always return a value
If no return value is given
undefined
is returnedIf invoked with
new
and no return is given the new object is returnedvar Car = function (speed) { this.speed = speed; }; var my_car = new Car('40 k/h');
Functions: Scope
No block scope
Only function scope
var foo = function () { var a = 3, b = 5; var bar = function () { var b = 7, c = 11; a += b + c; }; bar(); };
Functions: Closure
Inner functions have access to outer function's parameters and variables.
var elevator_maker = function() { var level = 1; var get_level = function() { return "level: " + level; } return { up: function(n) { level += n; return get_level(); }, down: function(n) { level -= n; return get_level(); }, }; }; var elevator = elevator_maker(); elevator.up(3); // level: 4 elevator.down(1); // level: 3
Functions: Module
Can eliminate the use of global variables
var elevator = function() { var level = 1; var get_level = function() { return "level: " + level; } return { up: function(n) { level += n; return get_level(); }, down: function(n) { level -= n; return get_level(); }, }; }(); elevator.up(3); // level: 4 elevator.down(1); // level: 3
Functions: Memoization
Remember the results of previous operations
var fibonacci = function (n) { return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); }; var fibonacci = function () { var memo = {0: 0, 1: 1}; return function fib (n) { var result = memo[n]; if (typeof result !== 'number') { result = fib(n - 1) + fib(n - 2); memo[n] = result; } return result; }; }(); fibonacci(10) // 55
Inheritance: Pseudoclassical
Intended to look sort of object-oriented
Provided by using
new
prefixHides the true nature of the language
var Vehicle = function(name){ this.name = name; }; Vehicle.prototype.get_name = function(){ return this.name; }; var vehicle = new Vehicle('Just a ride'); var Car = function(name, racing){ this.name = name; this.racing = racing; }; Car.prototype = vehicle; var my_car = new Car('My car', false); my_car.get_name(); // 'My car' my_car.racing; // false
Inheritance: Prototypal
A new object can inherit the properties of an old object
Start with a useful object and then make many more like it
var vehicle = { name: 'Just a ride', get_name: function(){ return this.name; } }; var my_car = Object.create(vehicle); my_car.name = 'My car' my_car.racing = false; my_car.get_name(); // 'My car' my_car.racing; // false
Inheritance: Functional
Allows privacy
var vehicle = function(spec) { spec.name = spec.name || 'Just a ride'; var that = {}; that.get_name = function(){ return spec.name; }; return that; }; var car = function(spec) { spec.racing = !! spec.racing; var that = vehicle(spec); that.is_racing = function(){ return spec.racing; }; return that; }; my_car = car({name: 'My car', racing: false}); my_car.get_name(); // 'My car' my_car.is_racing(); // false
Arrays
Array-like objects
Linked to Array.prototype
No linear allocated memory or computed offest access
Have their own literal notation
Elements can be of any value
Arrays
Array literal
var a = []; var misc = [ 'string', 98.6, true, null, undefined, ['nested', 'array'], {x: 1}, Infinity ];
length property is not upper bound
var a = []; a.length // 0 a[10] = 1; a.length // 11 a[4] // undefined
Have methods
var a = []; a.push(1); a // [1]
Bad parts
Global variables
No block scope
Semicolon insertion
return { status: true }; return { status: true };
Bad parts
floating point
Phony arrays
+ overloading
1 + 2 // 3 '1' + 2 // '12' 1 + '2' // '12'
typeof
typeof null // object typeof [] // object
Bad parts
eval
Bitwise operators
==
'' == '0' // false 0 == '' // true 0 == '0' // true false == 'false' // false false == '0' // true false == undefined // false false == null // false null == undefined // true ' \t\r\n ' == 0 // true
References
JavaScript: The Good Parts
by Douglas Crockford