Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save BrianWill/6be0ab040e44974fc865a0c9f7f348ac to your computer and use it in GitHub Desktop.
Save BrianWill/6be0ab040e44974fc865a0c9f7f348ac to your computer and use it in GitHub Desktop.
Javascript expressions, variables, arrays, and objects

Values and variables

A value is a piece of data. We have several data types in Javascript:

  • number
  • boolean
  • string
  • array
  • object
  • function

We also have the special values null and undefined.

In Javascript, all variables are reference variables, meaning that they store addresses, not values.

// each assignment stores the address of the value in the variable foo
var foo = 3;
foo = "hi";
foo = false;

A variable we create outside any function is global. A variable we create within a function is local to that function. The parameters of a function are local variables of that function.

(If you assign to a variable name that does not exist, Javascript will create a global variable of that name. This is a terrible mistake in the design of the language. Only assign to variables that have been explicitly created with var or which are function parameters.)

Statements and expressions

A Javascript program is a series of statements. There are several kinds of statements, each with their own syntax and semantics. The most essential statements are:

  • var statement
  • function statement
  • return statement
  • if statement
  • while statement
  • for statement
  • for...in statement
  • break statement
  • continue statement
  • try statement
  • block statement (a set of curly braces containing a list of statements)
  • expression statement

An expression is anything which returns a value. This includes variables, operations, function calls, and values themselves:

3       // returns the value 3
'hi'    // returns the value 'hi'
2 + 5   // returns the value 7 
foo     // returns the value referenced by the variable foo
foo()   // returns the value returned by calling the function referenced by the variable foo
foo[0]  // returns the value referenced as the first element of the array referenced by the variable foo
foo.bar // returns the value of the property bar of the object referenced by the variable foo

The syntax of an expression statement is an expression followed by a semi-colon:

foo();  // an expression statement

When an expression statement is executed, the expression is evaluated. In real code, expression statements are always function calls because any other kind of expression in an expression statement does nothing useful.

The operands to an operator are expressions. If an operand expression returns the wrong kind of value for the operation, the operation throws an exception:

foo() * 7   // if foo() returns something other than a number, the * operation throws an exception

An expression can be surrounded in any number of unncessary parens:

// these are all equivalent expressions
foo           
(foo)         
((foo))      
(((foo)))     
((((foo))))    

When an expression is suffixed with parens, the value returned by the expression is called as a function. If the value returned is not a function, an exception is thrown.

foo(3)()         // call the value returned by foo(3) as a function with no arguments
foo(3)('hi', 7)  // call the value returned by foo(3) as a function with arguments 'hi' and 7
bar[6]()         // call the value returned by bar[6] as a function with no arguments

Arrays

A new array is created with a pair of square brackets. The array can be given initial values with a list of expressions inside, separated by commas:

var arr = [];            // store in the variable arr the address of a new, empty array
arr = [7, 'hi', true];  // store in the variable arr the address of a new array with the values 7, 'hi', and true

Like a Javascript variable, a Javascript array actually stores addresses rather than values:

var arr = []; 
arr[0] = 3;     // store the address of the value 3 as the first element of the array
arr[1] = "hi";  // store the address of the string "hi" as the second element of the array
arr[2] = [];    // store the address of a new array as the third element of the array
arr[3] = arr;   // store the address of the array itself as its fourth element

Javascript arrays can increase in size dynamically, so we can assign to any numeric index at any time. An index that has never been assigned a value has the value undefined. An array's .length property is always one greater then the array's largest index:

var arr = [];
console.log(arr.length);   // 0 (because the array is empty)
arr[3] = true;   // store the address of true as the fourth element of the array
arr[1] = false;  // store the address of false as the second element of the array
console.log(arr.length);   // 4 (because the largest index is currently 3)
console.log(arr);          // [undefined, false, undefined, true]

Objects

What Javascript calls an 'object' is in other languages called a 'map', 'hashmap', or 'dictionary'. An object stores an unordered collection of key-value pairs, where the keys are all strings but their associated values can be of any type. (Again, like Javascript variables and arrays, a Javascript object really stores addresses, not values.)

Javascript calls each key-value pair a 'property'. An object is created with the syntax {}, and initial properties can be listed inside:

var obj = {};  // store in the variable obj the address of a new, empty object

// store in the variable obj the address of a new object with 
// two properties: 'hi' with the value 3, and 'yo' with the value false
obj = {'hi': 3, 'yo': false};  

If a property name (the key) conforms to identifier rules (i.e. it contains only alphanumeric characters, underscores, and dollar signs), then you can omit the quote marks:

 // the property names 'hi' and 'yo' can be written without surrounding quote marks
var obj = {hi: 3, yo: false, 'foo bar': 7}; 

To access/modify/add object properties, use the [] operator with a string expression inside the brackets:

var obj = {hi: 3, yo: false, 'foo bar': 7};
console.log(obj['hi']);   // 3
obj['foo bar'] =  9;   // assign the 'foo bar' property the value 12
obj['moose'] = true;   // create new property 'moose' and assign it the value true
function foo() {
    return 'elephant';
}
obj[foo()] = 12;      // create new property 'elephant' and assign it the value 12

If a property name conforms to identifier rules, we can use the . operator instead of []:

var obj = {hi: 3, yo: false, 'foo bar': 7};
console.log(obj.hi);   // 3
obj['foo bar'] =  9;   // cannot use the dot operator because 'foo bar' has a space 
obj.moose = true;
function foo() {
    return 'elephant';
}
obj[foo()] = 12;   // cannot use the dot operator 

Object prototypes

When created, an object can be linked to an already existing object. This pre-existing object is then the prototype of the new object. There are a few ways to create an object with a prototype, but this is the most straight-forward:

var foo = {};
var bar = Object.create(foo);  // returns a new object which has the object of foo as its prototype

When we retrieve property values from an object, if the object does not itself have a property of the specified name, then Javascript will look for the value of the same property name in the prototype. If not found there, Javascript will look in the prototype of the prototype (if it has one), recursively.

var foo = {x: 3};
var bar = Object.create(foo);  // returns a new object which has the object of foo as its prototype
var ack = Object.create(bar);  // returns a new object which has the object of bar as its prototype

// so now ack links to bar, which links to foo
console.log(foo.x);   // 3
console.log(bar.x);   // 3
console.log(ack.x);   // 3

foo.x = 4;
console.log(foo.x);   // 4
console.log(bar.x);   // 4
console.log(ack.x);   // 4

bar.x = 9;       // now bar has its own x
console.log(foo.x);   // 3
console.log(bar.x);   // 9
console.log(ack.x);   // 9

ack.x = -5;       // now ack has its own x
console.log(foo.x);   // 3
console.log(bar.x);   // 9
console.log(ack.x);   // -5

// none of the objects have a property 'y'
console.log(foo.y);   // undefined
console.log(bar.y);   // undefined
console.log(ack.y);   // undefined

So what are prototypes good for? Javascript uses them to enable an Object-Oriented style of programming. A prototype object can stand in as a sort of class:

var MyClass = {
    // these functions are the methods of the class
    foo: function() {},
    bar: function() {}
};

function MyClassConstructor(x, y) {
    // all instances will have MyClass as their prototype
    var o = Object.create(MyClass);
    // create the fields of the new instance 
    o.x = x;
    o.y = y;
    return o;
}

Any instance we create with MyClassConstructor will have MyClass as its prototype, so we can have instances which all share the same set of methods. If MyClass itself has a prototype, that prototype object would represent the parent class of MyClass. By constructing a tree of prototypes, we can have a class hierarchy.

Though strings are not objects, they actually have a prototype object, which contains several useful methods:

var s = 'hello';

// (the string is passed to the function as the special parameter 'this')
console.log(s.toUpperCase());  // 'HELLO' 

Likewise, numbers have a prototype object with number methods, and arrays have a prototype object with array methods.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment