UNB/ CS/ David Bremner/ teaching/ cs2613/ labs/ Lab 10

Background


Methods

Time
10 minutes
Activity
Demo

We can use JavaScript objects in a simple way by e.g. naming conventions for functions.

function timePlus(time1, time2) {
    let mins = (time1.mins + time2.mins) % 60;
    let hours = time1.hours + time2.hours + Math.floor((time1.mins+time2.mins)/60);
    return {'hours': hours, 'mins': mins};
}

console.log(timePlus({hours: 10, mins:30}, {hours: 17, mins:47}));

If we want to have "time" objects with a "plus" method, one way is to add that method manually. In order for that to work, we need to make use of the JavaScript variable this. When the function method is called as object.method(), the special variable this is defined to mean the current object. We can use this to wrap our existing function as a method.

function maketime(hours, mins){
    let plus=function (other) {
        let raw=timePlus(this,other);
        return ______________________________
    };

    return { 'hours': hours, 'mins': mins, 'plus': plus};
}

let A=maketime(10, 30);
let B=maketime(17, 47);
let C=A.plus(B);
console.log(C);

Protypes

Time
15 minutes
Activity
Individual work

Adding methods manually to newly created objects is a bit confusing and verbose, so JavaScript has the notion of a 'prototype',

let protoTime = {
    plus: function(other) {
        let raw=timePlus(this,other);
        return timeNew(raw.hours, raw.mins);
    }
};

In the following code, the method plus is inherited from the prototype, but the fields hours and minutes are not. Fill in the blanks to get the following code working.

function timeNew(hours, mins) {
    let obj=Object.create(protoTime);
    _______________;
    _____________;
    return obj;
}

D=timeNew(21,42);
E=timeNew(17,37);

F=D.plus(E);
console.log(F);

The benefit is not huge here, but you can see how it would help if there were many methods, all creating new objects.

Classes (are really about prototypes)

Time
5 minutes
Activity
Demo

In practice it's not usual to call object.create directly with the prototype object, but rather to use new keyword, along with the prototype property of a constructor.

function Time(hours, mins){
    this.hours=hours;
    this.mins=mins;
}

Time.prototype.plus=function (other) {
    let raw=timePlus(this,other);
    return ______________________________;
}

G = new Time(20,59);
H = new Time(11,11);

I=G.plus(H);
console.log(I);

Finally, ES2015 provides the class keyword to concisely generate constructors and prototypes.

class Time2 {
    constructor(hours, mins){
        this.hours=hours;
        this.mins=mins;
    };
    plus(other) {
        let raw=timePlus(this,other);
        ______________________________________;
    }
}

Time2;

J= new Time2(5,30);
K= new Time2(11,55);

L=J.plus(K); 

It's important to keep in mind that this is just convenience syntax for the same prototype based system.

JavaScript Arrays

Time
20 minutes
Activity
Exercise from book

JavaScript supports arrays. They are actually implemented as objects, which leads to some slightly surprising behaviour:

> x=[]
> x[10]=1
> x
> x["10"] === x[10]

Follow the (first part of the) Sum of a Range Exercise to write a range function that passes the following tests.

describe("range", function () {
    it("empty", function () {
        expect(array.range(2,1)).toEqual([]);
    });
    it("single", function () {
        expect(array.range(2,2)).toEqual([2]);
    });
    it("multiple", function () {
        expect(array.range(42,50)).toEqual([42,43,44,45,46,47,48,49,50]);
    });
});

Arrays Continued

Time
20 minutes
Activity
Exercise from book

Follow the (second part of the) Sum of a Range Exercise to write a sum function that passes the following tests.

describe("sum", function () {
    it("empty", function () {
        expect(array.sum([])).toBe(0);
    });
    it("single", function () {
        expect(array.sum([2])).toBe(2);
    });
    it("multiple", function () {
        expect(array.sum(array.range(1,10))).toBe(55);
    });    
});

Array methods

Time
10 minutes
Activity
Demo

It turns out that JavaScript arrays have some useful higher order methods, i.e. methods that take functions as arguments.

    function average (array) {
        return array.reduce((a,b) =>     , 0)/array.length;
    }
    console.log(average([1,2,3]));
    function average2 (array) {
        let sum=0;
        array.forEach( (a) =>       );
        return sum/array.length;
    }

Recursion in Javascript

Time
20 Minutes
Activity
Individual
    function plus(a,b) {
        if (a === 0) {
            return b;
        } else {
            return plus(a-1, b+1);
        }
    }

    function mult(a,b) {
        if (a===0) {
            return 0;
        } else {

        }
    }
(define (mult a b)
  (cond
    [(zero? a) 0]
    [else (plus (mult (sub1 a) b) b)]))