Objects
...so, I guess this involves declaring a new class, giving it various public/private attributes and methods, and then using a constructor to bring one into existence.
NO!
> person = {name: "pat", age: 47}
Object {name: "pat", age: 47}
> person.name
"pat"
> person["name"]
"pat"
> person["Name"]
undefined
> property = "name"
"name"
> person[property]
"pat"
> person["property"]
undefined
Object Comparison
> me = person
Object {name: "pat", age: 47}
> me === person
true
> impostor = {name: "pat", age: 47}
Object {name: "pat", age: 47}
> imposter === me
false
The full rules for comparison are summarised
here.
Some painful workarounds to support unit-testing
here.
Cloning objects is
difficult too.
Object Mutation
> person
Object {name: "pat", age: 47}
> me
Object {name: "pat", age: 47}
> impostor
Object {name: "pat", age: 47}
> me.age += 1
48
> me.job = "programmer" // creating a new member "on the fly"!
"programmer"
> me
Object {name: "pat", age: 48, job: "programmer"}
> person
Object {name: "pat", age: 48, job: "programmer"}
> impostor
Object {name: "pat", age: 47}
Object Property Ordering
(and the lack thereof)
> orderTest = {foo:"foo", 3:3, 2:2, 1:1, bar:"bar", 99:99}
Object {1: 1, 2: 2, 3: 3, 99: 99, foo: "foo", bar: "bar"}
The ordering of properties is not guaranteed,
and shouldn't be relied upon.
Different implementations do it differently,
and they are free to change at any time.
It is an "implementation detail".
Inspecting Stuff
This is very useful...
> console.dir(me)
V Object
age: 48
job: "programmer"
name: "pat"
>__proto__: Object
This exposes the true inner structure of objects, including the "secret" links to the prototype chain.
Also, in Chrome, you can use "
dir" as a shortcut.
Messing With Arrays
Try evaluating 'a' and expanding 'dir(a)' after each line:
> a
["apple", 99, "cherry", undefined × 2, "pear"]
> a[2] = [10, 20, 30]
[10, 20, 30]
> a[2] = person
Object {name: "pat", age: 48, job: "programmer"}
> a.crazy = "madness"
"madness"
> a[1.5] = "WTF!"
"WTF!"
> a[Math.PI] = "delicious!"
"delicious!"
> a[-5] = "You must be kidding!"
"You must be kidding!"
> a[10] = a // "INCEPTION!!!"
["apple", 99, Object, undefined × 2, "pear", undefined × 4, Array[11]]
Differences between
JavaScript and Java...
Dynamic Typing
Variables do not have explicit fixed types in JS.
A variable can hold a reference to any
type of data
i.e. the language is "dynamically typed"
(like Python and Ruby and LISP),
rather than "statically typed"
(like C++, Java and Pascal).
Dynamic typing can often be quite convenient and flexible,
but it can also be a source of confusion and error.
Objects and Classes
JavaScript has "objects", but it doesn't define them via "classes". In fact, JavaScript objects are really just flexible associative-arrays (also known as "maps" or "dictionaries").
They contain a set of arbitrary <name>:<value> pairs, where the <name> has to be a string, but the <value> can be anything (including other "objects").
You can change the set of <names> (aka "properties") which an object has at runtime i.e. you can add, modify, or remove things whenever you like.
Prototypes
JavaScript removes the conventional Object Oriented distinction between "object" instances and the "classes" which define their properties and behaviours.
Instead, object instances may "inherit" behaviour directly from each other. When an object is created it may nominate another object as its "prototype" and, in so doing, the prototype becomes a kind of parent object which implements default behaviour, which the child may then over-ride in the conventional manner.
First Class Functions
In JavaScript, functions are "data" too. This means that you can assign them to variables, and pass them in and out of other functions. You can also create them at runtime.
This turns out to be an immensely powerful facility,
and is the central requirement for being a so-called
"functional" language.
In fact, this feature is often used to work-around the other deficiencies of the language.
Numbers
In JavaScript, there is only one numeric type:
double-precision floating-point
There is no dedicated "integer" type (but you can, of course, use doubles to represent integers as long as you are careful with them).
Error-Checking
Ha!
In JavaScript, everything happens at runtime, and there is no (conventional) "compilation" phase at which basic errors can be detected for you.
There is very little "sanity checking" and the language is highly (and, arguably, dangerously) permissive.
Programming errors tend to manifest as runtime errors, and sometimes in quite non-obvious ways.
JavaScript gives you enough rope to hang yourself with.
JavaScript in the Browser
Basic Browser Architecture:
[URL] -> Fetch -> [Cache]
[Cache] -> Parse -> [Tree]
[Tree] -> Flow -> [Display List]
[Display List] -> Paint -> [Pixels]
Enter Scripting
Flow -> Paint -> Event -> Script -> Flow ->
..and repeat
Embedding Scripts
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Trivial Script Embedding</title>
</head>
<body>
<div id="output"></div>
<script src="myScript.js"></script>
</body>
</html>
NB: HTML5 validated via
myScript.js
// Output to console, and to my special "output" element.
output = function (thing) {
console.log(thing);
document.getElementById("output").innerHTML += thing + "<br>";
};
// The simplest "useful" function: return `x` squared
square = function (x) {
return x * x;
};
output(square(5));
output(square(10));
output("");
...or, in an actual web-page,
here
Criticism
From Crockford's "JavaScript: The Good Parts"...
The Awful Parts
- Global Variables
- Scope
- Semicolon Insertion
- Reserved Words
- Unicode
- typeof
- +
- Floating Point
- NaN
- Phony Arrays
- Falsy Values
The Bad Parts
- ==
- with
- eval
- continue
- switch fall-through
- Blockless statements
- ++ and --
- Bitwise operators
- "function" as a statement
- new
Equality
"...but some are more equal than others"
> 0 == "0"
true
> 0 == ""
true
> "" == 0
true
> "" == "0"
false
i.e. == is not transitive!
Use === (and !==) instead, always.
Taming The Beast
Use a "safe" subset of the language, use "strict" mode,
and run your code against a "lint" tool which detects
violations and likely errors.
Crockford's own:
A more tolerant alternative: