Object-Oriented Programming
Describe the following object oriented programming concepts: →
- inheritance - basing a class off of another class so that it maintains the same behavior as its super class
- polymorphism - having the same interface to instances of different types
- encapsulation - information hiding, internals/implementation details not accessible publicly
- abstraction - (again) creating tools / interfaces that allow a programmer to address the actual problem they're solving rather than having to deal with necessary, but irrelevant (to the problem) details
Object-Oriented Programming in Java
In Java, what language features / constructs allow inheritance, polymorphism, encapsulation, and abstraction? →
- inheritance - subclassing… using extend
- polymorphism - instances of different classes that are subclasses of the same superclass
- encapsulation - private methods and private members variables
- abstraction - creating classes, interfaces, abstract classes, and methods
Object-Oriented Programming in JavaScript
Although JavaScript has objects, its approach to object-oriented programming is a bit unconventional.
- it still supports encapsulation, inheritance, polymorphism, and abstraction
- … but it does so differently than Java (and other languages that support classical object-oriented techniques) →
- inheritance - prototypes and/or functions
- polymorphism - duck typing
- encapsulation - closures
- abstraction - higher order functions, prototypes, etc.
Globals
First off, in both Node and browser-based JavaScript implementations a global object exists:
global
for node
window
for browsers
Let's see what this looks like by: →
- checking out global in the interactive shell
- inadvertently creating a global variable within a function definition (dropping
const
, let
, and var
)
console.log(global.mistake);
function oopsGlobal() {
mistake = "yup";
}
oopsGlobal();
console.log(mistake);
console.log(global.mistake);
Methods
Methods are object properties that are functions (a function within the context of an object).
const cat = {};
cat.speak = function() {
console.log("meow");
};
cat.speak();
Notice that you can attach methods to any arbitrary object instance! (???)
This
Calling a function is called as a method - such as object.someFunction()
— the special variable this
in its body will reference the object that the method was called on. What will be printed out in the code below?. →
function speak() {
if(this.nationality == "Japanese") {
console.log("nyan");
} else if (this.nationality == "American") {
console.log("meow");
} else {
console.log("default cat noise");
}
}
const japaneseCat = {nationality:"Japanese", speak:speak};
const americanCat = {nationality:"American", speak:speak};
japaneseCat.speak();
americanCat.speak();
nyan
meow
In methods, this
refers to the object that the method was called on
Strict Mode / ESM Regular Function Invocation
When in strict mode (which is default when using ES Modules), this
is undefined
if a function is called on its own (that is, as a regular function invocation). What will the following code print out? →
const f = function() {
console.log('this is', this);
}
f();
In "Sloppy" Mode, this
in Regular Function Invocation
Things are much worse when you're not using ES Modules and you don't have strict mode on:
global.outside = 5;
const f = function() {
console.log(this.outside);
}
f();
5
Standalone Functions and This
Aaaand… assuming ES Modules, what's the output of our speak function from the previous slide if we call it on its on (not within the context of an object)? →
function speak() {
if(this.nationality == "Japanese") {
console.log("nyan");
} else if (this.nationality == "American") {
console.log("meow");
} else {
console.log("default cat noise");
}
}
speak();
This will actually cause an error! this
is undefined
, and looking up a property on undefined
causes a runtime error
Another Way(s)
Besides method invocation and regular function invocation, what are two other ways of executing a function? →
call
- invoke function that call was called on with specified this
and positional arguments
apply
- invoke function that apply was called on with specified this
and an Array
containing positional arguments
When invoking a function with call
or apply
:
this
will be bound to the value passed in as the first argument.
- What's the output of the following code? →
function greet(person) { console.log(this.greeting, person); }
const obj = { greeting: 'hi' };
greet.call(obj, 'joe');
hi joe
Call and Apply Continued
Aaaand… of course, call and apply with our cat example (modified a bit). What is the output of this code? →
function speak(how, toWho) {
const d = {Japanese: "nyans", American: "meows"};
const noise = d[this.nationality] || "default cat noise";
console.log(noise, how, 'at', toWho);
}
const cat = {nationality: "American"}
speak.apply(cat, ['loudly', 'you']);
speak.apply({}, ['softly', 'me']);
meows loudly at you
default cat noise softly at me
When executing a function with the methods call
or apply
, this
refers to the object passed in as the first argument to either method
Another Mystery?
What is the output of this code and why (assume ES Modules)? →
const counter = {numbers: [1, 2, 3, 4], animal:'owl'};
counter.count = function() {
this.numbers.forEach(function(n) {
console.log(n, this.animal + (n > 1 ? 's' : ''));
});
};
counter.count();
error - `this` is `undefined`
The anonymous function is being invoked as a regular function for every element in the Array
, counter.numbers
. this
refers to undefined
, which causes an error on property lookup
Same as Previous, but "Sloppy"
If the previous were run in sloppy mode (that is, not and ES Module and no use strict) →
1 'undefined'
2 'undefineds'
3 'undefineds'
4 'undefineds'
In sloppy mode, the this
in the inner function is not invoked as a method, but instead as a regular function. Consequently (in sloppy mode), this
is the global object.
Arrow Functions
In previous slides, we said that the this
value in arrow functions is the this
in the scope that the arrow function was created in (that is, it doesn't have it's own this
, it just uses the one that's already there!
Let's see how this works: →
const counter = {numbers: [1, 2, 3, 4], animal:'owl'};
counter.count = function() {
this.numbers.forEach((n) => {
console.log(n, this.animal + (n > 1 ? 's' : ''));
});
};
counter.count();
1 'owl'
2 'owls'
3 'owls'
4 'owls'
Better! this
is whatever this
refers to in the count method, and because count
was invoked as a method, this
is the object that count
was called on.
Arrow Functions Continued
Of course, that means if we use the following code, what will this
refer to? What is the output of the following code? →
function foo() {
const bar = (x) => { console.log(this.qux); };
bar();
}
foo();
undefined
this
references this
in the function, foo
, which was invoked as a regular function. Consequently, this
is the global object.
Summary
What is this?????
- regular function invocation
- in ES Modules / strict mode,
this
is undefined
- in sloppy mode,
this
is the global object
- method call
this
is the object the method was called on
- invoked with call or apply
this
is the first argument passed in to call or apply
- arrow function
this
is this
from the enclosing context