WebFund 2024F Lecture 22
Video
Video from the lecture for December 3, 2024 is now available:
Notes
Lecture 22 ---------- Last class is Thursday - will go over Assignment 4 solutions then Assignment 4 is due Wednesday night - accepted until 11:30 AM on Thursday - no time for extensions, sorry A3 & A4 will be graded before the final exam on Dec 12, 9 AM I've sent out emails for interviews - if you got one, please schedule one or contact me if you can't find a slot Openstack - will be open through exam - I'll send out notice, but please back up your work soon after the exam I will be conducting interviews after the final exam - will take place the week of Dec 16th - only requires 15 minutes, no prep needed Q&A session? - I could do one on Dec. 10th, during regular class time Last lecture quiz will be for today - officially due Friday, but will give a few extra days to submit Exam will be on the code from Assignment 4 - it has everything we've covered! Strict mode - original javascript was VERY loose, made it hard to see when you made an error - strict mode catches a lot of errors - in particular, assigning to a variable that hasn't been declared - Deno defaults to strict mode - node does not! - JavaScript modules default to strict mode To ensure strict mode - put "use strict"; before any other code (with quotes) at top of file - can also enable per function, just put "use strict"; at the top While strict mode will detect assigning to undeclared variables, it won't stop assignment to undefined properties of objects. Objects, prototypes, & classes ------------------------------ JavaScript is an object-oriented language - it does support inheritance & classes, even though we haven't used them in class While JavaScript supports classes and has special syntax for it, this support is mostly "syntactic sugar" - the underlying functionality was already there JavaScript's model is prototype-based inheritance, not class-based inheritance - in the end, we just have objects - to inherit, we have a prototype chain - if an object doesn't have a property or method, we check its prototypes for the functionality, going back in a chain So if you want to do inheritance, you can inherit from *any* object - you just set it as the prototype for the new object But doesn't that mean that the prototype could change at runtime? - YES - this can be a good thing or a bad thing, depending - but it is dynamic As you might notice, I'm really bad with doing object-based inheritance in JavaScript - that's because I don't like inheritance, I just use objects as key-value stores - and I instead use functions So what does "new" and "this" do? - this has the value of the object a function is associated with - if it is just a bare function, this has no value (undefined) - if you call the function with "new", then this has the value of {}, and is what the function returns normally - this empty object will have the prototype of the function, so in this case the function is acting as a constructor If I want an object with methods, I just make an object and assign methods to its properties - if I want that method to access the object, I use "this" - rather than use new, just make a function that returns the object you want Note that modules are almost class-like in JavaScript - when you import, you can assign all exported values (functions, variables, constants) to properties of an object - see what we did with authdb.js - so prototype-based inheritance isn't used that often in modern javascript
Code
Note the code below is different from that shown in lecture. In particular, the prototype-based example now works, as I fumbled this in lecture. As you can see below, you can approximate the functionality of JavaScript classes with prototypes, but it isn't exactly the same.
If you're wanting to create an object hierarchy in modern JavaScript, use classes. But Object.create() gives fine-grained control that can be useful for "mixins" or other more advanced inheritance patterns (has-a rather than is-a inheritance).
// Class example
class Rectangle {
name = "Rectangle"
// joke is only accessible from the class object
// but is also available in inheriting class objects
static joke = "I'm not classy"
constructor(height, width) {
this.height = height;
this.width = width;
}
area() {
return this.width * this.height;
}
}
class Square extends Rectangle {
name = "Square"
constructor(size) {
super(size, size);
}
}
var s = new Square(4);
s.area(); // 16
s.name; // "Square"
s.joke; // undefined
Square.joke // "I'm not classy"
Rectangle.joke // "I'm not classy"
// with prototypes & Object.create()
function Oval(width, height) {
// Classes don't need the check below,
// they automatically generate an error
// if you call the constructor without new
if (!this) {
console.error("Please call with new");
return;
}
this.width = width;
this.height = height;
}
Oval.joke = "I'm really not classy";
Oval.prototype.name = "Oval";
Oval.prototype.area = function () {
return Math.PI * this.height * this.width;
};
function Circle(r) {
return Oval.call(this, r, r);
}
Circle.prototype = Object.create(Oval.prototype, {
constructor: {
value: Circle,
enumerable: false,
writeable: true,
configurable: true,
},
});
Circle.prototype.name = "Circle";
var c = new Circle(4);
c.area(); // 50.26548245743669
c.name; // "Circle"
c.joke; // undefined
Circle.joke // undefined
Oval.joke // "I'm really not classy";