WDIM387 Week 3
JavaScript Objects
Instructor: Dan Muzyka
danmuzyka.ai@gmail.com
Object Literals
var dracula = {
name: "Dracula",
age: 582,
hungry: true,
bloodSupply: 0.2,
feedOn: function(person) {
if (this.bloodSupply < 1) {
person.bloodSupply -= 0.1;
this.bloodSupply += 0.1;
}
}
};
Object Literals
Handy for one-offs (singletons), but what if you need a bunch of similar objects?
var dracula = {
name: "Dracula",
age: 582,
hungry: true,
bloodSupply: 0.2,
feedOn: function(person) {
if (this.bloodSupply < 1) {
person.bloodSupply -= 0.1;
this.bloodSupply += 0.1;
}
}
};
var lestat = {
name: "Lestat",
age: 252,
hungry: true,
bloodSupply: 0.2,
feedOn: function(person) {
if (this.bloodSupply < 1) {
person.bloodSupply -= 0.1;
this.bloodSupply += 0.1;
}
}
};
Constructors
No classes in JavaScript, but you can use constructor functions.
var Vampire = function (name, age, hungry, bloodSupply) {
this.name = name || "Dracula";
this.age = age || 500;
this.hungry = hungry || true;
this.bloodSupply = bloodSupply || 0.2;
this.feedOn = function(person) {
if (this.bloodSupply < 1) {
person.bloodSupply -= 0.1;
this.bloodSupply += 0.1;
}
};
};
var dracula = new Vampire();
var lestat = new Vampire("Lestat", 232);
What are some potential problems with this approach?
Prototypes
If you want to share a property or method across objects (instead of creating a new copy of it in memory each time), add to the prototype.
var Vampire = function (name, age, hungry, bloodSupply) {
this.name = name || "Dracula";
this.age = age || 500;
this.hungry = hungry || true;
this.bloodSupply = bloodSupply || 0.2;
};
Vampire.prototype.feedOn = function(person) {
if (this.bloodSupply < 1) {
person.bloodSupply -= 0.1;
this.bloodSupply += 0.1;
}
};
var dracula = new Vampire();
var lestat = new Vampire("Lestat", 232);
Constructor Limitations
What happens if you forget the new keyword?
var Vampire = function (name, age, hungry, bloodSupply) {
this.name = name || "Dracula";
this.age = age || 500;
this.hungry = hungry || true;
this.bloodSupply = bloodSupply || 0.2;
};
Vampire.prototype.feedOn = function(person) {
if (this.bloodSupply < 1) {
person.bloodSupply -= 0.1;
this.bloodSupply += 0.1;
}
};
var dracula = Vampire();
var lestat = Vampire("Lestat", 232);
console.log(dracula);
console.log(lestat);
console.log(age);
console.log(hungry);
Constructor Pattens Enforcing "new"
Factory function pattern:
var Vampire = function (name, age, hungry, bloodSupply) {
var that = {
"name": name || "Dracula",
"age": age || 500,
"hungry": hungry || true,
"bloodSupply": bloodSupply || 0.2
}
return that;
};
var dracula = Vampire();
var lestat = Vampire("Lestat", 232);
What are some potential problems with this approach?
Constructor Pattens Enforcing "new"
Prototyping issue with factory function approach:
var Vampire = function (name, age, hungry, bloodSupply) {
var that = {
"name": name || "Dracula",
"age": age || 500,
"hungry": hungry || true,
"bloodSupply": bloodSupply || 0.2
}
return that;
};
Vampire.prototype.feedOn = function(person) {
if (this.bloodSupply < 1) {
person.bloodSupply -= 0.1;
this.bloodSupply += 0.1;
}
};
var dracula = Vampire();
var lestat = Vampire("Lestat", 232);
dracula.feedOn(lestat); // TypeError: dracula.feedOn is not a function
Constructor Pattens Enforcing "new"
Self-invoking constructor pattern:
var Vampire = function (name, age, hungry, bloodSupply) {
if (!(this instanceof Vampire)) {
return new Vampire(name, age, hungry, bloodSupply);
}
this.name = name || "Dracula";
this.age = age || 500;
this.hungry = hungry || true;
this.bloodSupply = bloodSupply || 0.2;
};
var dracula = new Vampire();
var lestat = Vampire("Lestat", 232);
Inheritance
var Undead = function() {
if (!(this instanceof Undead)) {
return new Undead();
}
this.alive = false;
this.animate = true;
// Dynamic Prototype Pattern
// This only evaluates to true the first time this function runs.
if (typeof this.attackHuman !== "function") {
Undead.prototype.attackHuman = function () {
console.log("Attacking a human!");
};
}
};
// Vampire constructor here...
// Create an Undead object and assign it as the prototype for Vampire
Vampire.prototype = new Undead();
var dracula = new Vampire();
console.log(dracula.alive);
dracula.attackHuman();
Inheritance
// Undead constructor...
// Vampire constructor...
Vampire.prototype.feedOn = function(person) {
if (this.bloodSupply < 1) {
person.bloodSupply -= 0.1;
this.bloodSupply += 0.1;
}
};
Vampire.prototype = new Undead();
var dracula = new Vampire();
var lestat = Vampire("Lestat", 232);
dracula.feedOn(lestat); // TypeError: dracula.feedOn is not a function
Inheritance
// Undead constructor...
// Vampire constructor...
Vampire.prototype = new Undead();
Vampire.prototype.feedOn = function(person) {
if (this.bloodSupply < 1) {
person.bloodSupply -= 0.1;
this.bloodSupply += 0.1;
}
};
var dracula = new Vampire();
var lestat = Vampire("Lestat", 232);
dracula.feedOn(lestat); // This works
Inheritance
Inheritance is dynamic:
// Undead constructor...
// Vampire constructor...
Vampire.prototype = new Undead();
var dracula = new Vampire();
Undead.prototype.moan = function() {
console.log("Mmmmwwaaaaa...!");
};
dracula.moan();
Inheritance
You can override inherited methods and properties:
// Undead constructor...
// Vampire constructor...
Vampire.prototype = new Undead();
var dracula = new Vampire();
Undead.prototype.moan = function() {
console.log("Mmmmwwaaaaa...!");
};
dracula.moan();
Vampire.prototype.moan = function() {
console.log("Blwa!");
};
dracula.moan();
Inheritance
Determine if an object property is on the object itself, or somewhere else up the prototype chain.
// Undead constructor...
// Vampire constructor...
Vampire.prototype = new Undead();
var dracula = new Vampire();
Undead.prototype.moan = function() {
console.log("Mmmmwwaaaaa...!");
};
Vampire.prototype.moan = function() {
console.log("Blwa!");
};
console.log(dracula.hasOwnProperty("moan")); // What do you think?
console.log("moan" in dracula);
Inheritance
Limitations of the factory function approach:
var Vampire = function (name, age, hungry, bloodSupply) {
var that = {
"name": name || "Dracula",
"age": age || 500,
"hungry": hungry || true,
"bloodSupply": bloodSupply || 0.2
}
return that;
};
Vampire.prototype.feedOn = function(person) {
if (this.bloodSupply < 1) {
person.bloodSupply -= 0.1;
this.bloodSupply += 0.1;
}
};
var dracula = Vampire();
var lestat = Vampire("Lestat", 232);
dracula.feedOn(lestat); // What happens here?
Inheritance
Problems with reference type properties on prototypes.
// Vampire constructor...
Vampire.prototype.victims = [];
var dracula = Vampire();
var lestat = Vampire("Lestat", 232);
dracula.victims.push("John");
dracula.victims.push("Jane");
console.log(dracula.victims);
console.log(lestat.victims);
Break
Video
Discuss Video
Lab Time
Start homework and reading for next week.
WDIM387 Week 3JavaScript Objects
By danmuzyka
WDIM387 Week 3JavaScript Objects
- 1,212