Java scriptconfusingbits

264
JAVASCRIPT: THE CONFUSING BITS JSON Dean cf.Objective() 2014

description

 

Transcript of Java scriptconfusingbits

Page 1: Java scriptconfusingbits

JAVASCRIPT: THE CONFUSING BITSJSON Dean

cf.Objective() 2014

Page 2: Java scriptconfusingbits

Who am I?

This guy

Otherwise nobody

Page 3: Java scriptconfusingbits

ARE YOU CONFUSED?I was

JavaScript is the most confusing thing I have ever tried to learn

Page 4: Java scriptconfusingbits

JavaScript is not your parents’ programming language

No Classes

Unusual inheritance

Changing scopes

Weird object creation

Functions with functions

Unusual variable behavior

Page 5: Java scriptconfusingbits

What this session isn’t

This session is not an intro to JavaScript

You have worked with JavaScript for a while

This session is not about politics, muscle cars, your DVR, or anything else you may find confusing

Page 6: Java scriptconfusingbits

Scoping

Page 7: Java scriptconfusingbits

ScopingJavaScript Scopes !== C-Style Scopes

JavaScript does not have block scope

CFML developers are used to this

If you create a variable it does NOT live in the context of the “block” where it was created (if, loop, etc).

The variable lives in the execution context where is was created

Execution context was a new term for me

Page 8: Java scriptconfusingbits

Function ScopeJavaScript has “function scope” or “execution context”

When a variable is created, it is created in that scope

The execution context where it was created

The function in which it was created

var x = 1; function doSomething() { for (i = 1; i < 10; i++) { x += i; } } doSomething(); console.log(x);

Page 9: Java scriptconfusingbits

Function ScopeJavaScript has “function scope” or “execution context”

When a variable is created, it is created in that scope

The execution context where it was created

The function in which it was created

var x = 1; function doSomething() { for (i = 1; i < 10; i++) { x += i; } } doSomething(); console.log(x);

Variable created in the global scope

Page 10: Java scriptconfusingbits

Function ScopeJavaScript has “function scope” or “execution context”

When a variable is created, it is created in that scope

The execution context where it was created

The function in which it was created

var x = 1; function doSomething() { for (i = 1; i < 10; i++) { x += i; } } doSomething(); console.log(x);

Variable from the global scope is used

Page 11: Java scriptconfusingbits

Function ScopeJavaScript has “function scope” or “execution context”

When a variable is created, it is created in that scope

The execution context where it was created

The function in which it was created

var x = 1; function doSomething() { for (i = 1; i < 10; i++) { x += i; } } doSomething(); console.log(x);

Variable from the global scope was updated by

doSomething()

Page 12: Java scriptconfusingbits

var x = 1; function doSomething() { var x = 1; for (i = 1; i < 10; i++) { x += i; } console.log( "Function Scope Variable: " + x); } doSomething(); console.log( "Global Scope Scope Variable: " + x);

Function ScopeJavaScript has “function scope” or “execution context”

When a variable is created, it is created in that scope

The execution context where it was created

The function in which it was created

var x = 1; function doSomething() { for (i = 1; i < 10; i++) { x += i; } } doSomething(); console.log(x);

Page 13: Java scriptconfusingbits

var x = 1; function doSomething() { var x = 1; for (i = 1; i < 10; i++) { x += i; } console.log( "Function Scope Variable: " + x); } doSomething(); console.log( "Global Scope Scope Variable: " + x);

Function ScopeJavaScript has “function scope” or “execution context”

When a variable is created, it is created in that scope

The execution context where it was created

The function in which it was created

var x = 1; function doSomething() { for (i = 1; i < 10; i++) { x += i; } } doSomething(); console.log(x);

Variable created in the global scope

Page 14: Java scriptconfusingbits

var x = 1; function doSomething() { var x = 1; for (i = 1; i < 10; i++) { x += i; } console.log( "Function Scope Variable: " + x); } doSomething(); console.log( "Global Scope Scope Variable: " + x);

Function ScopeJavaScript has “function scope” or “execution context”

When a variable is created, it is created in that scope

The execution context where it was created

The function in which it was created

var x = 1; function doSomething() { for (i = 1; i < 10; i++) { x += i; } } doSomething(); console.log(x);

Another variable created in the scope of the doSomething()

function scope

Page 15: Java scriptconfusingbits

var x = 1; function doSomething() { var x = 1; for (i = 1; i < 10; i++) { x += i; } console.log( "Function Scope Variable: " + x); } doSomething(); console.log( "Global Scope Scope Variable: " + x);

Function ScopeJavaScript has “function scope” or “execution context”

When a variable is created, it is created in that scope

The execution context where it was created

The function in which it was created

var x = 1; function doSomething() { for (i = 1; i < 10; i++) { x += i; } } doSomething(); console.log(x);

The function scope variable was changed

Page 16: Java scriptconfusingbits

var x = 1; function doSomething() { var x = 1; for (i = 1; i < 10; i++) { x += i; } console.log( "Function Scope Variable: " + x); } doSomething(); console.log( "Global Scope Scope Variable: " + x);

Function ScopeJavaScript has “function scope” or “execution context”

When a variable is created, it is created in that scope

The execution context where it was created

The function in which it was created

var x = 1; function doSomething() { for (i = 1; i < 10; i++) { x += i; } } doSomething(); console.log(x);

The global scope variable was unchanged

Page 17: Java scriptconfusingbits

var x = 1; function doSomething() { var x = 1; for (i = 1; i < 10; i++) { x += i; } console.log( "Function Scope Variable: " + x); } doSomething(); console.log( "Global Scope Scope Variable: " + x);

Function ScopeJavaScript has “function scope” or “execution context”

When a variable is created, it is created in that scope

The execution context where it was created

The function in which it was created

var x = 1; function doSomething() { for (i = 1; i < 10; i++) { x += i; } } doSomething(); console.log(x);

Page 18: Java scriptconfusingbits

Variable Hoisting

“JavaScript is the world’s most misunderstood programming

language” !

- Douglas Crockford

Page 19: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

Consider this simple example

Page 20: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

Consider this simple example

Any reasonable person would look at

this and say…

Page 21: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

Consider this simple example

OK… I’m creating a variable called foo

Page 22: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

Consider this simple example

And a function called bar()

Page 23: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

Consider this simple example

Then I’m calling bar()

Page 24: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

Consider this simple example

bar() checks to see if foo is defined

Page 25: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

Consider this simple example

If foo isn’t defined, then it gets defined with a value of 10

Page 26: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

Consider this simple example

Then foo gets logged out

Page 27: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

Consider this simple exampleWell, we know foo is defined, with a

value of 1.

Page 28: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

Consider this simple example

So this should log a 1, right?

Page 29: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

Consider this simple example

Page 30: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

Consider this simple example

Wait… what?

Page 31: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

Consider this simple example

Page 32: Java scriptconfusingbits

So what happened?

What we just saw is confusing

Why is the value 10 and not 1?

The answer is a combination of

Function Scope

And variable hoisting

Page 33: Java scriptconfusingbits

So what is variable hoisting?Function and Variable declarations get “hoisted” to the top of the executable context

Functions first

Then variables

So the JavaScript engine is rewriting our code

Let’s see how

Page 34: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

Page 35: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our codebar() is a function, so it gets hoisted first to

the top of the execution context

Page 36: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

In the case, it is the global context

Page 37: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

Page 38: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

Next our variables get hoisted.

Page 39: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

Next our variables get hoisted.

Wait… did he says “variableS”? There’s one variable, it’s foo,

right?

Page 40: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

function bar() { var foo; if (foo == undefined) { foo = 10; } console.log(foo); } !var foo; foo = 1; bar();

Page 41: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

function bar() { var foo; if (foo == undefined) { foo = 10; } console.log(foo); } !var foo; foo = 1; bar();

So our foo variable from the global scope got hoisted,

though not very far.

Page 42: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

function bar() { var foo; if (foo == undefined) { foo = 10; } console.log(foo); } !var foo; foo = 1; bar();

It is now at the top of the global execution context,

below any function from the same context.

Page 43: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

function bar() { var foo; if (foo == undefined) { foo = 10; } console.log(foo); } !var foo; foo = 1; bar();

But what’s this? Our foo variable in the function also got

hoisted to the top of its execution context.

Page 44: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

function bar() { var foo; if (foo == undefined) { foo = 10; } console.log(foo); } !var foo; foo = 1; bar();

So we (or at least, I) thought that the if statement was

checking to see if the global variable existed.

Page 45: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

function bar() { var foo; if (foo == undefined) { foo = 10; } console.log(foo); } !var foo; foo = 1; bar();

But after JavaScript’s rewrite we see it is actually checking to see if this variable is undefined.

!Is it?

Page 46: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

function bar() { var foo; if (foo == undefined) { foo = 10; } console.log(foo); } !var foo; foo = 1; bar();

A variable that has not been assigned a value is

of type undefined. !

-MDN

Page 47: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

function bar() { var foo; if (foo == undefined) { foo = 10; } console.log(foo); } !var foo; foo = 1; bar();

So foo is undefined! It exists, but has not been given a value

Page 48: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

function bar() { var foo; if (foo == undefined) { foo = 10; } console.log(foo); } !var foo; foo = 1; bar();

So foo receives a value of 10 because it is previously

undefined

Page 49: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

function bar() { var foo; if (foo == undefined) { foo = 10; } console.log(foo); } !var foo; foo = 1; bar();

This foo remains unchanged in the global scope. If we were to

log again here, we’d see a 1

Page 50: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

function bar() { var foo; if (foo == undefined) { foo = 10; } console.log(foo); } !var foo; foo = 1; bar();

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Page 51: Java scriptconfusingbits

Variable Hoisting

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } bar();

JavaScript rewriting our code

function bar() { if (foo == undefined) { var foo = 10; } console.log(foo); } !var foo = 1; bar();

function bar() { var foo; if (foo == undefined) { foo = 10; } console.log(foo); } !var foo; foo = 1; bar();

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Page 52: Java scriptconfusingbits

So why did this happen?

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

It gets more confusing

Page 53: Java scriptconfusingbits

So why did this happen?

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

It gets more confusing

We’ll make a small change to this code

Page 54: Java scriptconfusingbits

So why did this happen?

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

It gets more confusing

We’ll make a small change to this code

var foo = 1; function bar() { if (foo == undefined) { foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Page 55: Java scriptconfusingbits

So why did this happen?

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

It gets more confusing

var foo = 1; function bar() { if (foo == undefined) { foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Did you see it?

Page 56: Java scriptconfusingbits

So why did this happen?

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

It gets more confusing

var foo = 1; function bar() { if (foo == undefined) { foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Right there. I took out the var

Page 57: Java scriptconfusingbits

So why did this happen?

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

It gets more confusing

var foo = 1; function bar() { if (foo == undefined) { foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

So now what happens?

Page 58: Java scriptconfusingbits

So why did this happen?

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

It gets more confusing

var foo = 1; function bar() { if (foo == undefined) { foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Page 59: Java scriptconfusingbits

So why did this happen?

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

It gets more confusing

var foo = 1; function bar() { if (foo == undefined) { foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Page 60: Java scriptconfusingbits

So why did this happen?

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

It gets more confusing

var foo = 1; function bar() { if (foo == undefined) { foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Exactly what we expected to happen

the first time!

Page 61: Java scriptconfusingbits

So why did this happen?

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

It gets more confusing

var foo = 1; function bar() { if (foo == undefined) { foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Huh?

Page 62: Java scriptconfusingbits

So why did this happen?

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

It gets more confusing

var foo = 1; function bar() { if (foo == undefined) { foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Page 63: Java scriptconfusingbits

var?So all we did was remove var from the variable assignment

Why does that matter?

Again, this will be familiar to CFML developers

The use of var will cause the creation of the variable in the local scope (the execution context)

Failure to use var will result in the JS engine searching through the scope chain for the variable

If it doesn’t find the variable by the time it reaches the global scope, it will create it there

Page 64: Java scriptconfusingbits

var

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Let’s look at this again

Page 65: Java scriptconfusingbits

var

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Let’s look at this againHere we might think that the variable will only be created if the if statement evaluates to

true

Page 66: Java scriptconfusingbits

var

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Let’s look at this again

var foo = 1; function bar() { var foo; if (foo == undefined) { foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

But after that variable is hoisted we can see that it will

exist (though it will be undefined) regardless of the if

statement

Page 67: Java scriptconfusingbits

var

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Let’s look at this again

var foo = 1; function bar() { var foo; if (foo == undefined) { foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

It doesn’t matter that the variable already exists here, because this is in a different

scope

Page 68: Java scriptconfusingbits

var

var foo = 1; function bar() { if (foo == undefined) { var foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Let’s look at this again

var foo = 1; function bar() { var foo; if (foo == undefined) { foo = 10; } console.log( "Function Scope Variable: " + foo); } bar(); console.log( "Global Scope Variable: " + foo);

Page 69: Java scriptconfusingbits

No var

var foo = 1; function bar() { foo = 10; } bar(); console.log( "Global Scope Variable: " + foo);

One more time

Page 70: Java scriptconfusingbits

No var

var foo = 1; function bar() { foo = 10; } bar(); console.log( "Global Scope Variable: " + foo);

One more timeWhen var is not used in the assignment, the JavaScript engine will search for the

variable instead of creating it

Page 71: Java scriptconfusingbits

No var

var foo = 1; function bar() { foo = 10; } bar(); console.log( "Global Scope Variable: " + foo);

One more time

First it will look in the function context

Page 72: Java scriptconfusingbits

No var

var foo = 1; function bar() { foo = 10; } bar(); console.log( "Global Scope Variable: " + foo);

One more time

Then it will look in the next scope in the chain, in this case,

it is the global scope and it will find it.

Page 73: Java scriptconfusingbits

No var

var foo = 1; function bar() { foo = 10; } bar(); console.log( "Global Scope Variable: " + foo);

One more time

function bar() { foo = 10; } bar(); console.log( "Global Scope Variable: " + foo);

It it doesn’t find it in the global scope, it will create it there.

Page 74: Java scriptconfusingbits

PROTOTYPAL INHERITANCEObjects from Objects

Page 75: Java scriptconfusingbits

JavaScript PrototypesObjects inherit from objects. What could be more object oriented than that? - Douglas Crockford

In JavaScript objects can be created from other objects

This can be accomplished in several ways

Many consider it very elegant

Page 76: Java scriptconfusingbits

Classical Inheritance

Page 77: Java scriptconfusingbits

Classical InheritanceSuper-Class

Page 78: Java scriptconfusingbits

Classical Inheritance

Sub-Class

Page 79: Java scriptconfusingbits

Classical Inheritance

Page 80: Java scriptconfusingbits

Classical Inheritance

Page 81: Java scriptconfusingbits

Prototypal InheritanceCreating objects that inherit from other objects

Can only be done with two object creation methods

Constructor Functions

Object.create()

Either one is acceptable, but Object.create is recommended by many experts

Object.create() is not supported by all browsers, but that is easily fixed with Webshim Lib or other polyfills

Page 82: Java scriptconfusingbits

Prototypal Inheritance

Page 83: Java scriptconfusingbits

Prototypal InheritancePrototypes are how one object inherit

from another object

Page 84: Java scriptconfusingbits

Prototypal Inheritance

The inheritance “feels” like classical

OO inheritance when you use it

Page 85: Java scriptconfusingbits

Prototypal InheritanceBut internally, it is

very different

Page 86: Java scriptconfusingbits

Prototypal InheritanceEvery object has a

prototype, an object that it inherits from

Page 87: Java scriptconfusingbits

Prototypal Inheritance

The prototype of an object is actually a property of that

object

Page 88: Java scriptconfusingbits

Prototypal Inheritance

Unless you explicitly create one without.

Page 89: Java scriptconfusingbits

Prototypal Inheritance

Even then, it still has one, it is null

Page 90: Java scriptconfusingbits

Prototypal InheritanceEvery object has a __proto__ property

Every object has a __proto__ property

Every object has a __proto__ property

Every object has a __proto__ property

Every object has a __proto__ property

Page 91: Java scriptconfusingbits

Prototypal InheritanceEvery object has a __proto__ property

Every object has a __proto__ property

Every object has a __proto__ property

Every object has a __proto__ property

Every object has a __proto__ property

In modern browsers

Page 92: Java scriptconfusingbits

Prototypal Inheritance

Page 93: Java scriptconfusingbits

__proto__

__proto__ should NEVER be used in production (it is deprecated)

__proto__ is a great learning tool though

We can use __proto__ to look at an object’s prototype in the console

You can also access an object’s prototype using Object.getPrototypeOf(object) (using Webshim Lib to support older browsers)

Page 94: Java scriptconfusingbits

Prototypal Inheritancevar Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Page 95: Java scriptconfusingbits

Prototypal Inheritancevar Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Simplified example

Page 96: Java scriptconfusingbits

Prototypal Inheritancevar Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Create an object from which we will inherit

properties and methods

Page 97: Java scriptconfusingbits

Prototypal Inheritancevar Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Create a new object that inherits from Car (more on this in a bit)

Page 98: Java scriptconfusingbits

Prototypal Inheritancevar Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Assign a new property to the new object

Page 99: Java scriptconfusingbits

Prototypal Inheritancevar Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Call an inherited method, just to see if it

works

Page 100: Java scriptconfusingbits

Prototypal Inheritancevar Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Examine the new object

Page 101: Java scriptconfusingbits

Prototypal Inheritancevar Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Page 102: Java scriptconfusingbits

Prototypal Inheritance

Page 103: Java scriptconfusingbits

Prototypal InheritanceThe result

Page 104: Java scriptconfusingbits

Prototypal InheritanceThe result

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Page 105: Java scriptconfusingbits

Prototypal Inheritance

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Our inherited method ran

Page 106: Java scriptconfusingbits

Prototypal Inheritance

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Car is, indeed, the prototype of chevette

Page 107: Java scriptconfusingbits

Prototypal Inheritance

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

The new object

Page 108: Java scriptconfusingbits

Prototypal Inheritance

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

The new motor property of the

object

Page 109: Java scriptconfusingbits

Prototypal Inheritance

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

But wait… why doesn’t our object have a wheelCount

property or a go() method?

Page 110: Java scriptconfusingbits

Prototypal Inheritance

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

There they are, in the objects __proto__

property

Page 111: Java scriptconfusingbits

Prototypal Inheritance

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

But wait… the motor there is null. Can we access the wheelCount? How does

JavaScript know which motor to use?

Page 112: Java scriptconfusingbits

Prototypal Inheritance

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Page 113: Java scriptconfusingbits

Prototypal InheritanceWhen you request a property from an object:

JavaScript checks for that property in the object

If it does not exist, it checks the object’s prototype (__proto__)

If it does not exist, it checks the object’s prototype’s prototype

It continues until it reaches the top level object

This is referred to as the Prototype chain

If a property exists in more than one object in the prototype chain, the first one JS comes across is the one it will use

Page 114: Java scriptconfusingbits

Prototypal Inheritance

Page 115: Java scriptconfusingbits

Prototypal Inheritance

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

So if anything requests the motor property from

our chevette

Page 116: Java scriptconfusingbits

Prototypal Inheritance

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

It will find this one first in the chain

Page 117: Java scriptconfusingbits

Prototypal Inheritance

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Not this one

Page 118: Java scriptconfusingbits

Prototypal Inheritance

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

If chevette didn’t have a motor property, it

would find the one in the prototype

Page 119: Java scriptconfusingbits

Prototypal Inheritance

var Car = { wheelCount: 4, motor: null, go: function() { console.log( "Vrooooom!!!" ) }}; var chevette = Object.create( Car ); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( Car.isPrototypeOf( chevette ) ); console.log( chevette );

Page 120: Java scriptconfusingbits

Functions as First Class Objects

In JavaScript, Functions are first-class objects

They can have properties and methods of their own

They can be passed as arguments

They can be returned from functions

They can be properties of other objects

Page 121: Java scriptconfusingbits

Function PrototypesThis is where things get confusing

As we know, all objects have a prototype

That prototype is store internally in __proto__

Function Objects also have a prototype property, which we’ll refer to as the ‘Function Prototype’

The function prototype is NOT the function’s prototype (confused yet?)

The function object still has a __proto__ that contains its prototype

Page 122: Java scriptconfusingbits

Function PrototypesThis is where things get confusing

As we know, all objects have a prototype

That prototype is store internally in __proto__

Function Objects also have a prototype property, which we’ll refer to as the ‘Function Prototype’

The function prototype is NOT the function’s prototype (confused yet?)

The function object still has a __proto__ that contains its prototype

The function prototype is the object that will become the __proto__ property of

any new object created from that function if that function is used as a

constructor function

Page 123: Java scriptconfusingbits

Function PrototypesThis is where things get confusing

As we know, all objects have a prototype

That prototype is store internally in __proto__

Function Objects also have a prototype property, which we’ll refer to as the ‘Function Prototype’

The function prototype is NOT the function’s prototype (confused yet?)

The function object still has a __proto__ that contains its prototype

Page 124: Java scriptconfusingbits

Constructor Functions

Are just regular functions

When combined with the new keyword they behave differently

When used with new the function becomes a factory and creates a brand new object

this becomes bound to the new object being created

this is then automatically return by the constructor

Page 125: Java scriptconfusingbits

Constructor Functionsfunction Car() {} Car.prototype.wheelCount = 4; Car.prototype.motor = null; Car.prototype.go = function() { console.log( 'Vroooom!!!!' ); } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette ); !

Page 126: Java scriptconfusingbits

Constructor Functionsfunction Car() {} Car.prototype.wheelCount = 4; Car.prototype.motor = null; Car.prototype.go = function() { console.log( 'Vroooom!!!!' ); } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette ); !

Just a regular function

Page 127: Java scriptconfusingbits

Constructor Functionsfunction Car() {} Car.prototype.wheelCount = 4; Car.prototype.motor = null; Car.prototype.go = function() { console.log( 'Vroooom!!!!' ); } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette ); !

We then modify the function’s prototype to

add inheritable properties and methods

Page 128: Java scriptconfusingbits

Constructor Functionsfunction Car() {} Car.prototype.wheelCount = 4; Car.prototype.motor = null; Car.prototype.go = function() { console.log( 'Vroooom!!!!' ); } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette ); !

When we use the new keyword to create the

object…

Page 129: Java scriptconfusingbits

Constructor Functionsfunction Car() {} Car.prototype.wheelCount = 4; Car.prototype.motor = null; Car.prototype.go = function() { console.log( 'Vroooom!!!!' ); } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette ); !

Our regular function becomes a factory

function. !

Returns this automatically

Page 130: Java scriptconfusingbits

Constructor Functionsfunction Car() {} Car.prototype.wheelCount = 4; Car.prototype.motor = null; Car.prototype.go = function() { console.log( 'Vroooom!!!!' ); } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette ); !

Here is where the difference lies

Page 131: Java scriptconfusingbits

Constructor Functionsfunction Car() {} Car.prototype.wheelCount = 4; Car.prototype.motor = null; Car.prototype.go = function() { console.log( 'Vroooom!!!!' ); } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette ); !

The new object does not have Car() as its

prototype

Page 132: Java scriptconfusingbits

Constructor Functionsfunction Car() {} Car.prototype.wheelCount = 4; Car.prototype.motor = null; Car.prototype.go = function() { console.log( 'Vroooom!!!!' ); } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette ); !

It has Car()’s prototype as its prototype

Page 133: Java scriptconfusingbits

Constructor Functionsfunction Car() {} Car.prototype.wheelCount = 4; Car.prototype.motor = null; Car.prototype.go = function() { console.log( 'Vroooom!!!!' ); } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette ); !

So chevette.__proto__ == Car.prototype

Page 134: Java scriptconfusingbits

Constructor Functionsfunction Car() {} Car.prototype.wheelCount = 4; Car.prototype.motor = null; Car.prototype.go = function() { console.log( 'Vroooom!!!!' ); } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette ); !

Page 135: Java scriptconfusingbits

__proto__ and prototypeEvery object has a __proto__

__proto__ is a property

__proto__ references the object that is being inherited from

Only Function objects have a prototype property (in addition to __proto__)

A Function’s prototype references the object that will become the __proto__ property of new objects created from this function

if used as a constructor

Page 136: Java scriptconfusingbits

Constructor Functions

Page 137: Java scriptconfusingbits

Constructor FunctionsBehaves like our

Object.create() object

Page 138: Java scriptconfusingbits

Constructor Functions

It has a __proto__ like our Object.create() object

Page 139: Java scriptconfusingbits

Constructor FunctionsBut now we have this constructor property

Page 140: Java scriptconfusingbits

Constructor Functions

And in there is where we find the prototype object from which we

are inheriting

Page 141: Java scriptconfusingbits

Constructor Functions

So why all this prototype stuff?

Page 142: Java scriptconfusingbits

Constructor Functions

You said that the constructor automatically returns this, why

not just use that?

Page 143: Java scriptconfusingbits

Constructor Functions

Let’s try it

Page 144: Java scriptconfusingbits

Constructor Functions

Page 145: Java scriptconfusingbits

this

Page 146: Java scriptconfusingbits

this

function Car() { this.wheelCount = 4; this.motor = null; this.go = function () { console.log( 'Vrooommmm!!!' ); } } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette );

Page 147: Java scriptconfusingbits

this

function Car() { this.wheelCount = 4; this.motor = null; this.go = function () { console.log( 'Vrooommmm!!!' ); } } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette );

Just a regular function

Page 148: Java scriptconfusingbits

this

function Car() { this.wheelCount = 4; this.motor = null; this.go = function () { console.log( 'Vrooommmm!!!' ); } } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette );

We then modify the function’s this object to

add properties and methods

Page 149: Java scriptconfusingbits

this

function Car() { this.wheelCount = 4; this.motor = null; this.go = function () { console.log( 'Vrooommmm!!!' ); } } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette );

Remember, when we use new, this is bound

to the new object

Page 150: Java scriptconfusingbits

this

function Car() { this.wheelCount = 4; this.motor = null; this.go = function () { console.log( 'Vrooommmm!!!' ); } } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette );

So hey! Look! Our new object will have the

properties and methods, right?

Page 151: Java scriptconfusingbits

this

function Car() { this.wheelCount = 4; this.motor = null; this.go = function () { console.log( 'Vrooommmm!!!' ); } } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette );

The answer is YES. But they won’t be inherited

Page 152: Java scriptconfusingbits

this

function Car() { this.wheelCount = 4; this.motor = null; this.go = function () { console.log( 'Vrooommmm!!!' ); } } var chevette = new Car(); chevette.motor = { cylinder: 4 }; chevette.go(); console.log( chevette instanceof Car ); console.log( chevette );

Page 153: Java scriptconfusingbits

Prototypal Inheritance

Page 154: Java scriptconfusingbits

Prototypal InheritanceWorks similarly to our other examples

Page 155: Java scriptconfusingbits

Prototypal Inheritance

But, if we inspect the object we see…

Page 156: Java scriptconfusingbits

Prototypal Inheritance

The object has its own copy of the properties

and methods

Page 157: Java scriptconfusingbits

Prototypal Inheritance

It still has Car as its __proto__

Page 158: Java scriptconfusingbits

Prototypal Inheritance

And it would still inherit the properties and methods of Car’s

prototype

Page 159: Java scriptconfusingbits

Prototypal Inheritance

But, in this case, Car has no new properties and

methods

Page 160: Java scriptconfusingbits

Prototypal Inheritance

What we’ve created are instance variables

Page 161: Java scriptconfusingbits

Prototypal Inheritance

Page 162: Java scriptconfusingbits

Why not use this for everything?

When you use this new objects do not inherit those properties and methods

They get their own copies

If you change the this scope properties or methods in the prototype object the existing objects will not inherit the changes

The best option is to combine prototypal inheritance with instance variables to get what we want

Page 163: Java scriptconfusingbits

Prototypal InheritanceSo let’s think about how Car should work

We’ll create a new object that uses inherited and instance properties and methods to meet our needs

Car spec:

Each instance of Car should have its own name, wheelCount, color, and motor

All instances of Car should have the same methods for go(), addFuel(), brake(), and about()

Page 164: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ new Car('Chevette', 4, 'Black', 4), new Car('F-150', 4, 'Red', 8), new Car('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Page 165: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ new Car('Chevette', 4, 'Black', 4), new Car('F-150', 4, 'Red', 8), new Car('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Our Car constructor

Page 166: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ new Car('Chevette', 4, 'Black', 4), new Car('F-150', 4, 'Red', 8), new Car('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Of course, our constructor is only a

constructor if we remember to use new.

Page 167: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ new Car('Chevette', 4, 'Black', 4), new Car('F-150', 4, 'Red', 8), new Car('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Add our methods to the Car constructor’s

prototype

Page 168: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ new Car('Chevette', 4, 'Black', 4), new Car('F-150', 4, 'Red', 8), new Car('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

This method will be inherited from the

prototype

Page 169: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ new Car('Chevette', 4, 'Black', 4), new Car('F-150', 4, 'Red', 8), new Car('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

But when it access the this scope it will be getting instance variables

Page 170: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ new Car('Chevette', 4, 'Black', 4), new Car('F-150', 4, 'Red', 8), new Car('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

We’ll create some new Cars

Page 171: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ new Car('Chevette', 4, 'Black', 4), new Car('F-150', 4, 'Red', 8), new Car('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

And then do some stuff with them

Page 172: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ new Car('Chevette', 4, 'Black', 4), new Car('F-150', 4, 'Red', 8), new Car('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Page 173: Java scriptconfusingbits

Prototypal Inheritance

Page 174: Java scriptconfusingbits

Prototypal InheritanceAll of our inherited methods worked

correctly

Page 175: Java scriptconfusingbits

Prototypal Inheritance

And our instance variables are unique to

each instance

Page 176: Java scriptconfusingbits

Prototypal Inheritance

Page 177: Java scriptconfusingbits

Back to Object.create()

Page 178: Java scriptconfusingbits

Back to Object.create()

We look at prototypal inheritance with Object.create()

Page 179: Java scriptconfusingbits

Back to Object.create()

We look at prototypal inheritance with Object.create()

But we didn’t look at instance variables

Page 180: Java scriptconfusingbits

Back to Object.create()

We look at prototypal inheritance with Object.create()

But we didn’t look at instance variables

Let’s see how our Car example might look with instance variables

Page 181: Java scriptconfusingbits

var Car = { go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car, { name : { value: 'Chevette' }, wheelCount: { value: 4 }, color: { value : 'Black', writable: true }, motor: { value : { cylinders: 4 } } }), Object.create(Car, { name : { value: 'F-150' }, wheelCount: { value: 4 }, color: { value : 'Red', writable: true }, motor: { value : { cylinders: 8 } } }), Object.create(Car, { name : { value: 'Ram 3500' }, wheelCount: { value: 6 }, color: { value : 'Green', writable: true }, motor: { value : { cylinders: 10 } } })]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Page 182: Java scriptconfusingbits

var Car = { go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car, { name : { value: 'Chevette' }, wheelCount: { value: 4 }, color: { value : 'Black', writable: true }, motor: { value : { cylinders: 4 } } }), Object.create(Car, { name : { value: 'F-150' }, wheelCount: { value: 4 }, color: { value : 'Red', writable: true }, motor: { value : { cylinders: 8 } } }), Object.create(Car, { name : { value: 'Ram 3500' }, wheelCount: { value: 6 }, color: { value : 'Green', writable: true }, motor: { value : { cylinders: 10 } } })]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Simple object with methods to be inherited

Page 183: Java scriptconfusingbits

var Car = { go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car, { name : { value: 'Chevette' }, wheelCount: { value: 4 }, color: { value : 'Black', writable: true }, motor: { value : { cylinders: 4 } } }), Object.create(Car, { name : { value: 'F-150' }, wheelCount: { value: 4 }, color: { value : 'Red', writable: true }, motor: { value : { cylinders: 8 } } }), Object.create(Car, { name : { value: 'Ram 3500' }, wheelCount: { value: 6 }, color: { value : 'Green', writable: true }, motor: { value : { cylinders: 10 } } })]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Use Object.create to create new objects that

inherit from Car

Page 184: Java scriptconfusingbits

var Car = { go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car, { name : { value: 'Chevette' }, wheelCount: { value: 4 }, color: { value : 'Black', writable: true }, motor: { value : { cylinders: 4 } } }), Object.create(Car, { name : { value: 'F-150' }, wheelCount: { value: 4 }, color: { value : 'Red', writable: true }, motor: { value : { cylinders: 8 } } }), Object.create(Car, { name : { value: 'Ram 3500' }, wheelCount: { value: 6 }, color: { value : 'Green', writable: true }, motor: { value : { cylinders: 10 } } })]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

One way of getting instance variables

Page 185: Java scriptconfusingbits

var Car = { go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car, { name : { value: 'Chevette' }, wheelCount: { value: 4 }, color: { value : 'Black', writable: true }, motor: { value : { cylinders: 4 } } }), Object.create(Car, { name : { value: 'F-150' }, wheelCount: { value: 4 }, color: { value : 'Red', writable: true }, motor: { value : { cylinders: 8 } } }), Object.create(Car, { name : { value: 'Ram 3500' }, wheelCount: { value: 6 }, color: { value : 'Green', writable: true }, motor: { value : { cylinders: 10 } } })]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Is with this crap

Page 186: Java scriptconfusingbits

var Car = { go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car, { name : { value: 'Chevette' }, wheelCount: { value: 4 }, color: { value : 'Black', writable: true }, motor: { value : { cylinders: 4 } } }), Object.create(Car, { name : { value: 'F-150' }, wheelCount: { value: 4 }, color: { value : 'Red', writable: true }, motor: { value : { cylinders: 8 } } }), Object.create(Car, { name : { value: 'Ram 3500' }, wheelCount: { value: 6 }, color: { value : 'Green', writable: true }, motor: { value : { cylinders: 10 } } })]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

These are called property descriptors

Page 187: Java scriptconfusingbits

var Car = { go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car, { name : { value: 'Chevette' }, wheelCount: { value: 4 }, color: { value : 'Black', writable: true }, motor: { value : { cylinders: 4 } } }), Object.create(Car, { name : { value: 'F-150' }, wheelCount: { value: 4 }, color: { value : 'Red', writable: true }, motor: { value : { cylinders: 8 } } }), Object.create(Car, { name : { value: 'Ram 3500' }, wheelCount: { value: 6 }, color: { value : 'Green', writable: true }, motor: { value : { cylinders: 10 } } })]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

If you don’t explicitly specify writable, enumerable, or

configurable, they won’t be.

Page 188: Java scriptconfusingbits

var Car = { go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car, { name : { value: 'Chevette' }, wheelCount: { value: 4 }, color: { value : 'Black', writable: true }, motor: { value : { cylinders: 4 } } }), Object.create(Car, { name : { value: 'F-150' }, wheelCount: { value: 4 }, color: { value : 'Red', writable: true }, motor: { value : { cylinders: 8 } } }), Object.create(Car, { name : { value: 'Ram 3500' }, wheelCount: { value: 6 }, color: { value : 'Green', writable: true }, motor: { value : { cylinders: 10 } } })]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

So in this example, only color can be changed after the object is constructed

Page 189: Java scriptconfusingbits

var Car = { go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car, { name : { value: 'Chevette' }, wheelCount: { value: 4 }, color: { value : 'Black', writable: true }, motor: { value : { cylinders: 4 } } }), Object.create(Car, { name : { value: 'F-150' }, wheelCount: { value: 4 }, color: { value : 'Red', writable: true }, motor: { value : { cylinders: 8 } } }), Object.create(Car, { name : { value: 'Ram 3500' }, wheelCount: { value: 6 }, color: { value : 'Green', writable: true }, motor: { value : { cylinders: 10 } } })]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Page 190: Java scriptconfusingbits

Back to Object.create()

Page 191: Java scriptconfusingbits

Back to Object.create()

Other than the properties being non-writable, non-configurable, and non-enumerable (except for color) this

works the same as the other examples

Page 192: Java scriptconfusingbits

Back to Object.create()

But it sucks

Page 193: Java scriptconfusingbits

var Car = { init : function (name, wheelCount, color, cylinders) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : cylinders }; return this; }, go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car).init('Chevette', 4, 'Black', 4), Object.create(Car).init('F-150', 4, 'Red', 8), Object.create(Car).init('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Page 194: Java scriptconfusingbits

var Car = { init : function (name, wheelCount, color, cylinders) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : cylinders }; return this; }, go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car).init('Chevette', 4, 'Black', 4), Object.create(Car).init('F-150', 4, 'Red', 8), Object.create(Car).init('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

I think this is a bit easier to look at

Page 195: Java scriptconfusingbits

var Car = { init : function (name, wheelCount, color, cylinders) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : cylinders }; return this; }, go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car).init('Chevette', 4, 'Black', 4), Object.create(Car).init('F-150', 4, 'Red', 8), Object.create(Car).init('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

We create an init() method for all

objects to inherit

Page 196: Java scriptconfusingbits

var Car = { init : function (name, wheelCount, color, cylinders) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : cylinders }; return this; }, go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car).init('Chevette', 4, 'Black', 4), Object.create(Car).init('F-150', 4, 'Red', 8), Object.create(Car).init('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

This works just like our constructor

before

Page 197: Java scriptconfusingbits

var Car = { init : function (name, wheelCount, color, cylinders) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : cylinders }; return this; }, go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car).init('Chevette', 4, 'Black', 4), Object.create(Car).init('F-150', 4, 'Red', 8), Object.create(Car).init('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

But we must explicitly return this

Page 198: Java scriptconfusingbits

var Car = { init : function (name, wheelCount, color, cylinders) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : cylinders }; return this; }, go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car).init('Chevette', 4, 'Black', 4), Object.create(Car).init('F-150', 4, 'Red', 8), Object.create(Car).init('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Soooooo much better than those

property descriptors

Page 199: Java scriptconfusingbits

var Car = { init : function (name, wheelCount, color, cylinders) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : cylinders }; return this; }, go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car).init('Chevette', 4, 'Black', 4), Object.create(Car).init('F-150', 4, 'Red', 8), Object.create(Car).init('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Page 200: Java scriptconfusingbits

Back to Object.create()

Page 201: Java scriptconfusingbits

Back to Object.create()

Still working

Page 202: Java scriptconfusingbits

But wait… there’s more

Page 203: Java scriptconfusingbits

But wait… there’s more

We can use the same functions we were using before for constructors with Object.create()

Page 204: Java scriptconfusingbits

But wait… there’s more

We can use the same functions we were using before for constructors with Object.create()

The new object will still inherit from the function prototype

Page 205: Java scriptconfusingbits

But wait… there’s more

We can use the same functions we were using before for constructors with Object.create()

The new object will still inherit from the function prototype

But the constructor function never actually fires, so we can’t use it from constructing the object with instance variables

Page 206: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ Object.create(Car.prototype), Object.create(Car.prototype), Object.create(Car.prototype) ]; console.log(cars);

Page 207: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ Object.create(Car.prototype), Object.create(Car.prototype), Object.create(Car.prototype) ]; console.log(cars);

We can use a function

Page 208: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ Object.create(Car.prototype), Object.create(Car.prototype), Object.create(Car.prototype) ]; console.log(cars);

And modify its prototype

Page 209: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ Object.create(Car.prototype), Object.create(Car.prototype), Object.create(Car.prototype) ]; console.log(cars);

Then use Object.create()

Page 210: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ Object.create(Car.prototype), Object.create(Car.prototype), Object.create(Car.prototype) ]; console.log(cars);

Note we are passing in Car’s prototype, not Car

Page 211: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ Object.create(Car.prototype), Object.create(Car.prototype), Object.create(Car.prototype) ]; console.log(cars);

Car’s prototype is where the methods we

want to inherit are

Page 212: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ Object.create(Car.prototype), Object.create(Car.prototype), Object.create(Car.prototype) ]; console.log(cars);

Unfortunately, the constructor never runs, these variables are not

added as instance variables

Page 213: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ Object.create(Car.prototype), Object.create(Car.prototype), Object.create(Car.prototype) ]; console.log(cars);

Page 214: Java scriptconfusingbits

Back to Object.create()

Page 215: Java scriptconfusingbits

Back to Object.create()

Still inheriting the prototype’s methods

Page 216: Java scriptconfusingbits

Back to Object.create()

But no properties

Page 217: Java scriptconfusingbits

Back to Object.create()

Page 218: Java scriptconfusingbits

function Car() {}Car.prototype.init = function (name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; return this; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ Object.create(Car.prototype).init('Chevette', 4, 'Black', 4), Object.create(Car.prototype).init('F-150', 4, 'Red', 8), Object.create(Car.prototype).init('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Page 219: Java scriptconfusingbits

function Car() {}Car.prototype.init = function (name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; return this; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ Object.create(Car.prototype).init('Chevette', 4, 'Black', 4), Object.create(Car.prototype).init('F-150', 4, 'Red', 8), Object.create(Car.prototype).init('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

We could use property descriptors again… but

who’d want to?

Page 220: Java scriptconfusingbits

function Car() {}Car.prototype.init = function (name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; return this; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ Object.create(Car.prototype).init('Chevette', 4, 'Black', 4), Object.create(Car.prototype).init('F-150', 4, 'Red', 8), Object.create(Car.prototype).init('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

We can use an init() method again

Page 221: Java scriptconfusingbits

function Car() {}Car.prototype.init = function (name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; return this; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ Object.create(Car.prototype).init('Chevette', 4, 'Black', 4), Object.create(Car.prototype).init('F-150', 4, 'Red', 8), Object.create(Car.prototype).init('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Then call it like we did before after passing the function prototype into

Object.create()

Page 222: Java scriptconfusingbits

function Car() {}Car.prototype.init = function (name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; return this; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ Object.create(Car.prototype).init('Chevette', 4, 'Black', 4), Object.create(Car.prototype).init('F-150', 4, 'Red', 8), Object.create(Car.prototype).init('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Page 223: Java scriptconfusingbits

So???So which one should I use?!?!?!

I bet you were hoping for an answer

A lot of experts will tell you to use Object.create(). But which way should you use Object.create()?

Some will tell you that new is evil, others will tell you the truth. new is not evil

Pick one way and stick with it

My preference is for Object.create(SimpleObject).init() or new ConstructorFunction()

Page 224: Java scriptconfusingbits

var Car = { init : function (name, wheelCount, color, cylinders) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : cylinders }; return this; }, go : function () { console.log( 'Vrooommmm!!!' ); }, addFuel : function () { console.log( 'Fuel Added' ); }, brake : function () { console.log( 'Braking' ); }, about : function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } } var cars = [ Object.create(Car).init('Chevette', 4, 'Black', 4), Object.create(Car).init('F-150', 4, 'Red', 8), Object.create(Car).init('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

Object.create(SimpleObject).init()

Page 225: Java scriptconfusingbits

function Car(name, wheelCount, color, motorSize) { this.name = name; this.wheelCount = wheelCount; this.color = color; this.motor = { cylinders : motorSize }; } Car.prototype.go = function () { console.log( 'Vrooommmm!!!' ); }; Car.prototype.addFuel = function () { console.log( 'Fuel Added' ); }; Car.prototype.brake = function () { console.log( 'Braking' ); }; Car.prototype.about = function() { return 'The ' + this.name + ' has a ' + this.motor.cylinders + ' cylinder motor and ' + this.wheelCount + ' wheels. ' + 'This one is ' + this.color; } var cars = [ new Car('Chevette', 4, 'Black', 4), new Car('F-150', 4, 'Red', 8), new Car('Ram 3500', 6, 'Green', 10) ]; for (var car in cars) { console.log(cars[car].about()); cars[car].addFuel(); cars[car].go(); cars[car].brake(); }

new ConstructorFunction()

Page 226: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

Page 227: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

The makeAdder() function will create and a return a

new function

Page 228: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

Normally we would expect that when this function

finishes running…

Page 229: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

… that its scope would no longer exist, including the

howMuch argument

Page 230: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

When we call makeAdder()

Page 231: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

howMuch is equal to 5

Page 232: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

The function then returns another function (but does not

execute it)

Page 233: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

So how then, does howMuch still exist when …

Page 234: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

We call the new function

Page 235: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

Because the returned function is a closure

Page 236: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

Not only does it have access to its own scope,

where addTo exists

Page 237: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

It has access to the scope that it was in when it was

created

Page 238: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

Where howMuch exists and is equal to 5

Page 239: Java scriptconfusingbits

Closure Examplefunction makeAdder(howMuch) { return function (addTo) { return addTo + howMuch; } } //Make a 5 addervar add5 = makeAdder(5); //Make a 10 addervar add10 = makeAdder(10); console.log( add5(10) ); // 15console.log( add10(20) ); //30

Page 240: Java scriptconfusingbits

Closures

In basic terms, a Closure is a function that maintains the context in which is was created in addition to its own

I am not going to delve deeply into closures, Adam will do that later

Page 241: Java scriptconfusingbits

The changing this scopeA function that is the property of another object is called a “Method” of that object

When a method is called as a property of an Object, this refers back to the object

The object assigned to this changes depending on where and how the function is called

NOT by where or how it is defined

If you don’t call a function correctly, it could break

This is a source of confusion for many developers (me included)

Page 242: Java scriptconfusingbits

Changing this scopevar name = "Global"; var testObj = { name : "Test Object 1", about : function() { return this.name; } } var testObj2 = { name : "Test Object 2"} console.log( testObj.about() ); var outerAbout = testObj.about; console.log( outerAbout() ); testObj2.about = outerAbout; console.log( testObj2.about() );

Page 243: Java scriptconfusingbits

Changing this scopevar name = "Global"; var testObj = { name : "Test Object 1", about : function() { return this.name; } } var testObj2 = { name : "Test Object 2"} console.log( testObj.about() ); var outerAbout = testObj.about; console.log( outerAbout() ); testObj2.about = outerAbout; console.log( testObj2.about() );

Create a function that will return the value of this.name

Page 244: Java scriptconfusingbits

Changing this scopevar name = "Global"; var testObj = { name : "Test Object 1", about : function() { return this.name; } } var testObj2 = { name : "Test Object 2"} console.log( testObj.about() ); var outerAbout = testObj.about; console.log( outerAbout() ); testObj2.about = outerAbout; console.log( testObj2.about() );

Ensure name exists in all available scopes

Ensure name exists in all available scopes

Ensure name exists in all available scopes

Page 245: Java scriptconfusingbits

Changing this scopevar name = "Global"; var testObj = { name : "Test Object 1", about : function() { return this.name; } } var testObj2 = { name : "Test Object 2"} console.log( testObj.about() ); var outerAbout = testObj.about; console.log( outerAbout() ); testObj2.about = outerAbout; console.log( testObj2.about() );

Page 246: Java scriptconfusingbits

Changing this scopevar name = "Global"; var testObj = { name : "Test Object 1", about : function() { return this.name; } } var testObj2 = { name : "Test Object 2"} console.log( testObj.about() ); var outerAbout = testObj.about; console.log( outerAbout() ); testObj2.about = outerAbout; console.log( testObj2.about() );

Call about() on testObj

Page 247: Java scriptconfusingbits

Changing this scopevar name = "Global"; var testObj = { name : "Test Object 1", about : function() { return this.name; } } var testObj2 = { name : "Test Object 2"} console.log( testObj.about() ); var outerAbout = testObj.about; console.log( outerAbout() ); testObj2.about = outerAbout; console.log( testObj2.about() );

Add about() reference to a

global variable, call it again

Page 248: Java scriptconfusingbits

Changing this scopevar name = "Global"; var testObj = { name : "Test Object 1", about : function() { return this.name; } } var testObj2 = { name : "Test Object 2"} console.log( testObj.about() ); var outerAbout = testObj.about; console.log( outerAbout() ); testObj2.about = outerAbout; console.log( testObj2.about() );

Add about() reference to testObj2, call it again

Page 249: Java scriptconfusingbits

Changing this scopevar name = "Global"; var testObj = { name : "Test Object 1", about : function() { return this.name; } } var testObj2 = { name : "Test Object 2"} console.log( testObj.about() ); var outerAbout = testObj.about; console.log( outerAbout() ); testObj2.about = outerAbout; console.log( testObj2.about() );

All three about()s reference the same function

Page 250: Java scriptconfusingbits

Changing this scopevar name = "Global"; var testObj = { name : "Test Object 1", about : function() { return this.name; } } var testObj2 = { name : "Test Object 2"} console.log( testObj.about() ); var outerAbout = testObj.about; console.log( outerAbout() ); testObj2.about = outerAbout; console.log( testObj2.about() );

Page 251: Java scriptconfusingbits

Confusing

So what if we want to control the context?

We can define to which object this is bound

We can do this using call() and apply()

Page 252: Java scriptconfusingbits

Call vs. Apply

Each takes the function context as the first argument

That is the object that will become this

call() takes each additional argument as parameters to the function

apply() takes only one extra argument which is array of values that will be used as parameters to the function

Page 253: Java scriptconfusingbits

Defining this var name = "Global"; testObj = { name : "Test Object 1", about : function(additionalString) { return this.name + ' ' + additionalString; } } testObj2 = { name : "Test Object 2" } console.log( testObj.about("is awesome") ); var outerAbout = testObj.about; console.log( outerAbout.call(testObj, "Is Awesome") ); testObj2.about = outerAbout; console.log( testObj2.about.apply(testObj, ["is awesome"]) );

Page 254: Java scriptconfusingbits

Defining this var name = "Global"; testObj = { name : "Test Object 1", about : function(additionalString) { return this.name + ' ' + additionalString; } } testObj2 = { name : "Test Object 2" } console.log( testObj.about("is awesome") ); var outerAbout = testObj.about; console.log( outerAbout.call(testObj, "Is Awesome") ); testObj2.about = outerAbout; console.log( testObj2.about.apply(testObj, ["is awesome"]) );

Modified about() to take an argument

Page 255: Java scriptconfusingbits

Defining this var name = "Global"; testObj = { name : "Test Object 1", about : function(additionalString) { return this.name + ' ' + additionalString; } } testObj2 = { name : "Test Object 2" } console.log( testObj.about("is awesome") ); var outerAbout = testObj.about; console.log( outerAbout.call(testObj, "Is Awesome") ); testObj2.about = outerAbout; console.log( testObj2.about.apply(testObj, ["is awesome"]) );

Call about() normally, will be bound to testObj

Page 256: Java scriptconfusingbits

Defining this var name = "Global"; testObj = { name : "Test Object 1", about : function(additionalString) { return this.name + ' ' + additionalString; } } testObj2 = { name : "Test Object 2" } console.log( testObj.about("is awesome") ); var outerAbout = testObj.about; console.log( outerAbout.call(testObj, "Is Awesome") ); testObj2.about = outerAbout; console.log( testObj2.about.apply(testObj, ["is awesome"]) );

Call about() about from the global scope

using call()

Page 257: Java scriptconfusingbits

Defining this var name = "Global"; testObj = { name : "Test Object 1", about : function(additionalString) { return this.name + ' ' + additionalString; } } testObj2 = { name : "Test Object 2" } console.log( testObj.about("is awesome") ); var outerAbout = testObj.about; console.log( outerAbout.call(testObj, "Is Awesome") ); testObj2.about = outerAbout; console.log( testObj2.about.apply(testObj, ["is awesome"]) );

Passing in testObj will cause this to be bound

to testObj

Page 258: Java scriptconfusingbits

Defining this var name = "Global"; testObj = { name : "Test Object 1", about : function(additionalString) { return this.name + ' ' + additionalString; } } testObj2 = { name : "Test Object 2" } console.log( testObj.about("is awesome") ); var outerAbout = testObj.about; console.log( outerAbout.call(testObj, "Is Awesome") ); testObj2.about = outerAbout; console.log( testObj2.about.apply(testObj, ["is awesome"]) );

We pass in additional arguments, they will be passed on to about()

Page 259: Java scriptconfusingbits

Defining this var name = "Global"; testObj = { name : "Test Object 1", about : function(additionalString) { return this.name + ' ' + additionalString; } } testObj2 = { name : "Test Object 2" } console.log( testObj.about("is awesome") ); var outerAbout = testObj.about; console.log( outerAbout.call(testObj, "Is Awesome") ); testObj2.about = outerAbout; console.log( testObj2.about.apply(testObj, ["is awesome"]) );

Call about() from testObj2 using apply()

Page 260: Java scriptconfusingbits

Defining this var name = "Global"; testObj = { name : "Test Object 1", about : function(additionalString) { return this.name + ' ' + additionalString; } } testObj2 = { name : "Test Object 2" } console.log( testObj.about("is awesome") ); var outerAbout = testObj.about; console.log( outerAbout.call(testObj, "Is Awesome") ); testObj2.about = outerAbout; console.log( testObj2.about.apply(testObj, ["is awesome"]) );

Passing in testObj will cause this to be bound

to testObj

Page 261: Java scriptconfusingbits

Defining this var name = "Global"; testObj = { name : "Test Object 1", about : function(additionalString) { return this.name + ' ' + additionalString; } } testObj2 = { name : "Test Object 2" } console.log( testObj.about("is awesome") ); var outerAbout = testObj.about; console.log( outerAbout.call(testObj, "Is Awesome") ); testObj2.about = outerAbout; console.log( testObj2.about.apply(testObj, ["is awesome"]) );

We pass in additional arguments as an array of arguments, they will be passed on to about()

Page 262: Java scriptconfusingbits

Defining this var name = "Global"; testObj = { name : "Test Object 1", about : function(additionalString) { return this.name + ' ' + additionalString; } } testObj2 = { name : "Test Object 2" } console.log( testObj.about("is awesome") ); var outerAbout = testObj.about; console.log( outerAbout.call(testObj, "Is Awesome") ); testObj2.about = outerAbout; console.log( testObj2.about.apply(testObj, ["is awesome"]) );

Page 263: Java scriptconfusingbits

Defining this var name = "Global"; testObj = { name : "Test Object 1", about : function(additionalString) { return this.name + ' ' + additionalString; } } testObj2 = { name : "Test Object 2" } console.log( testObj.about("is awesome") ); var outerAbout = testObj.about; console.log( outerAbout.call(testObj, "Is Awesome") ); testObj2.about = outerAbout; console.log( testObj2.about.apply(testObj, ["is awesome"]) );

Page 264: Java scriptconfusingbits

Thank You

Questions?

!

Jason Dean

@jasonpdean

http://www.12robots.com