Skip to content
Permalink
7b4e193ca6
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
346 lines (276 sloc) 7.04 KB

Objects and Functions

JavaScript objects can be thought of as simple collections of name-value pairs. As such, they are similar to:

  • Dictionaries in Python
  • Hash tables in C and C++
  • Associative arrays in PHP

Here is a simple example.

var employee = {
  firstName: "Colin",
  lastName: "Stephen",
  department: "Computing",
  hireDate: new Date()
}

Name-Value Pairs

The “name” part is a JavaScript string (quotes if not a valid variable name).

age
"first name"
"age"

first name

The “value” can be any JavaScript value:

112233
"hello world"
function() {
  \\ do something
}
false

The preferred way to create objects in JS is using an “object literal”:

var empty_object = {}
var physicist = {
  "first-name": "Albert",
  "second-name": "Einstein"
  "age": 135
}

Remember that the value can be any JS value. That includes other objects. In other words: objects can be nested.

var flight = {
  airline: "BA",
  departure: {
    IATA: "SYD",
    time: "2014-09-22 14:45"
  },
  arrival: {
    IATA: "LAX",
    time: "2014-09-23 10:32"
  }
}

Object values can be retrieved in two ways: Use [ ] around a string with the name to retrieve as a suffix to the object name:

physicist["first-name"] // returns "Albert"
flight["number"] // returns 882

If the name is a legal JS name the . notation can be used:

flight.airline // returns 882
flight.departure.city // returns "Sydney"

Undefined Values

If you try to retrieve a nonexistent name from an object, JS returns undefined:

physicist["middle-name"] // returns undefined
flight.capacity // returns undefined

TIP: the OR operator || can be used to fill in “default” values:

var middle = physicist["middle-name"] || "(none)"
var capacity = flight.capacity || "unknown"

Undefined Objects

If you try to retrieve a value from an object that is undefined, JS throws a TypeError exception:

fakeObject["any-string"] // throw "TypeError"
flight.capacity // returns undefined
flight.capacity.minimum // throw "TypeError"

Avoiding TypeError

The AND operator && can be used to guard against this problem:

flight.capacity // undefined
flight.capacity.minimum // throw "TypeError"

flight.capacity && flight.capacity.minimum
// undefined

Setting object values at creation.

Object values are set in two ways:

During object creation, unless your object is empty {}:

var employee = {name: "Colin"};
employee.name // returns "Colin"

Setting values by assignment.

This sets a new value if the name does not already exist. Otherwise, it updates the existing value:

physicist["middle-name"] = "Bob";
physicist["middle-name"] // returns "Bob"
flight.arrival.city // returns "Los Angeles"
flight.arrival.city = {full: "Los Angeles", short: "LA"}
flight.arrival.city.short // returns "LA"

Call by reference.

Objects are passed around in JS programs “by reference”. They are never copied.

var a = {}
var b = {}
a.test = "hello"
b.test // returns undefined
var a = {};
var b = a;
a.test = "hello"
b.test // returns "hello"

Example.

var stooge = {first: "Jerome", second: "Howard"}
var x = stooge;
x.nickname = "Curly";
var nick = stooge.nickname;
nick // returns "Curly"

Function creation.

This creates a function object using a function literal

For example:
function add(x, y) {
  var total = x + y
  return total
}

Named functions.

The function can use its own name to call itself Useful for manipulating tree structures

var add = function(x, y) {
  var total = x + y
  return total
}

Defines an anonymous function and assigns it to the variable name add.

add could be reassigned later in the program.

Both anonymous and named functions are common in JS.

Invoking functions.

There are several ways to call a function:

  • method (part of an object)
  • function (stand-alone)
  • constructor (next week)
  • apply (next week)

Functions as object properties.

Methods are functions stored as properties of objects. When a method is invoked, this is bound to that object.

var myValueObject = {
  value: 0,
  increment: function(inc) {
    this.value += typeof inc === ’number’ ? inc : 1;
  }
}

myValueObject.increment();
myValueObject.value // returns 1
myValueObject.increment(2);
myValueObject.value // returns 3

Regular function invocation.

You have seen it, just use brackets after a direct reference to the function object.

add(3, 4); // returns 7

Contrast with method invocation which looks like:

myObject.methodName(3, 4);
myObject["methodName"](3, 4);

Constructors

new is strongly related to this:

  • creates a brand new empty object
  • calls the function specified
  • sets this to the new object
  • returns the new object

Functions that are designed to be called by ‘new’ are called “constructor functions”.

Constructor function invocation.

function Person(first, last) {
    this.first = first
    this.last = last
}
var s = new Person('Colin', 'Stephen')

Inheritance with prototypes.

If we can construct “classes”, how do we do inheritance in JS?

JS is a “prototypal” inheritance language.

Person.prototype.fullName = function() {
    return this.first + ' ' + this.last			
}

Person.prototype.fullNameReversed = function() {
    return this.last + ', ' + this.first
}

s.fullName() // returns "Simon Willison"

Function arguments.

Every function is passed an array-like object:

  • arguments like this it is available in all functions
  • Holds all of the values passed to the function
  • Useful when you want to work with an arbitrary number of arguments
function avg() { // no parameters
    var sum = 0
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments[i]						
    }
    return sum / arguments.length
}
				
avg(2, 3) // returns 2.5
avg(2, 3, 4, 5) // returns 3.5

ECMA 6 Classes

Not true classes and objects.

A simple way to work with the existing prototype-based inheritance.

Provide a much simpler and clearer syntax to create objects.

Must be defined before use (no 'hoisting')

module.exports = class Person {
  constructor(firstname, lastname) {
    this.first = firstname
    this.last = lastname
  }

  set firstName(name) {
    this.first = name
  }

  get name() {
    return `${this.first} ${this.last}`
  }
}

Subclassing.

const Person = require('./person')

module.exports = class Employee extends Person {

  constructor(firstname, lastname, grade = 1) {
    super(firstname, lastname)
    this.grade = grade
  }

  calculateSalary(months = 1) {
    return this.grade * 1000 * months
  }
}

Static Methods.

class Point {
    static distance(a, b) {
        return Math.abs(a - b)
    }
}

console.log(Point.distance(10, 42)) // 32

Creating objects.

const person = new Person('Andy', 'Capp')
console.log(person.name)
const manager = new Employee('Peter', 'Piper', 4)
console.log(manager.name)
console.log(manager.calculateSalary(6))
console.log(manager)