Objects and Prototypes Summary

CSCI-UA.0480-008

Objects

In JavaScript, an object is basically just a container of properties

  • properties have names and values
  • a property can be any string
  • values can be any value, including functions (called methods)

Accessing Properties

How can you get / retrieve a value that's associated with a property name from an object?

  • use dot notation: obj.propName
  • use bracket notation: obj[propName]
  • (use bracket notation for property names that aren't valid variable names or for dynamic property names)

Working With Objects

How do you add a new property and value pair to an object?

  • simply use the dot operator or bracket notation, and assignment
  • obj.newProp = newVal or obj[newProp] = newVal

How do you modify an existing property?

  • same as adding… dot operator or bracket notation, and assignment
  • obj.prop = newVal or obj[prop] = newVal

And finally, how do you remove a property?

  • use delete before referencing a property name
  • delete obj.prop

Prototype

JavaScript's objects are prototype based rather than class based:

  • an object can inherit properties from another object, its prototype
  • an object's prototype can also have a prototype!
  • this chain of prototypes usually ends with Object.prototype
  • a property is found by:
    • first looking if the object itself contains the property
    • then the object's prototype
    • …and the prototype's prototype
    • until it reaches an object with null as its prototype (such as Object.prototype)

Object.prototype

What methods does Object.prototype contain (we definitely know two)?

Getting an Object's Prototype

How do you retrieve an object's original prototype?

  • Use Object.getPrototypeOf
  • (note that attempting to access a property named .prototype on your object does not actually return your object's prototype!)
    • for example…
    • const obj = {};
    • console.log(Object.getPrototypeOf(obj));
    • console.log(obj.prototype); // <-- don't do this, you'll get undefined

Creating Objects

Name 4 ways to create objects.

  • object literals
  • Object.create
  • constructors
  • ES6 classes

Object Literals

You can create objects simply by using curly braces!

  • {} is an empty object
  • {name1:val1, name2:val2} … you can create property and value pairs
    • each property connected to a value with a colon
    • each pair separated by a comma

What do you think the prototype of an object created with an object literal is?


Object.getPrototypeOf({}) === Object.prototype

Object.create

How does Object.create work / what does it do?

You use Object.create(someOtherObject) to create objects with a specified prototype. The single argument passed in to Object.create becomes the new object's prototype.Let's see an example.


const cat = {cute: 'very'};
const kitten = Object.create(cat);
console.log(kitten.cute); // <-- kitten inherits cute from cat! 

Constructor

What's a constructor?

A constructor is a regular function called with new in front of it.


function Cat() { }
const c = new Cat();

Constructors and Properties

How can we set properties on all new objects created by a constructor?

Use this to refer to a fresh empty object that's returned by the constructor. Add properties to this to set properties on the newly created object. Let's see an example.


function Cat() { this.cute = 'very'; }
const c = new Cat();
const d = new Cat();
console.log(c.cute, d.cute); // <-- properties on new objects are set!

Using This Continued

Using this creates a property name and value for every new object instantiated with the constructor. Each object has its own copy. These properties are considered "own" properties (they haven't been inherited).


function Cat() { this.nicknames = ['katy furry', 'kitty wap']; }
const c = new Cat();
const d = new Cat();
d.nicknames.push('tail-fur swift');
console.log(c.nicknames, d.nicknames); // <-- properties are different!
console.log(c.hasOwnProperty('nicknames')); // <-- yup, bar is an 'own' property

Adding Properties Continued

You can also use the constructor's (the actual function object) own prototype (it's really called prototype!) property to set the properties on the prototype of all instances created by this constructor.


function Cat() { }
const c = new Cat();
Cat.prototype.cute = 'very';
console.log(c.cute); 
// ^-- such wow! c gained a new prop even though
// it was instantiated before setting a property
// on Cat's prototype object

Constructor's Prototype Property

Note that since we're setting properties on the prototype object, these properties are not own properties.


function Cat() { }
const c = new Cat();
Cat.prototype.cute = 'very';
console.log(c.cute); // <-- cute exists
console.log(c.hasOwnProperty(c.cute)); // <-- but it's inherited (not an own prop)

Constructor's Prototype Property Continued

You can also just assign an entire object to the prototype property… but this doesn't change all instances like setting individual properties on the constructor's prototype property does.


function Cat() { this.cute = 'very' }
function Kitten() { }
Kitten.prototype = new Cat();
const k = new Kitten(); // <-- instantiated *after* setting prototype!
console.log(k.cute); // <-- cute exists!

An ES6 Class Example

A base class:


class Monster {
    constructor(name) {
        this.name = name;
    }

    scare(thing) {
        console.log(this.name, ' scares ', thing); 
    }
}

A subclass:


class Werewolf extends Monster {
    constructor(name, type) {
        super(name);
        this.type = type; 
    }

    howl() {
        console.log(this.name, this.type, 'werewolf howls at the moon');
    }
}
const w = new Werewolf('wally', 'party');

Classes and Prototypes

So… classes essentially set up a prototype chain and constructor function. What's the output of this code?


console.log(typeof Werewolf);
console.log(Object.getPrototypeOf(w) === Werewolf.prototype);
console.log(Object.getPrototypeOf(w).hasOwnProperty('howl'));
console.log(Object.getPrototypeOf(w).hasOwnProperty('scare'));
console.log(Object.getPrototypeOf(Object.getPrototypeOf(w)) === Monster.prototype);
console.log(w instanceof Werewolf);
console.log(w instanceof Monster);

Function
true
true
false
true
true
true