The following are my notes for Codeschool.com Java Script Best Practices course: http://campus.codeschool.com/courses/javascript-best-practices/contents . The coarse mainly features how to create modules from your javascript code, in a way that is easy to manage. (Please also see the attached file for better formatting.)
JavaScript Best Practices
* notes 1.1
TERNARY CONDITIONALS
standard conditional
if (TRUE) {
i=1
} else {
i=2
}
ternary conditional
j==2 ? i=1 ; i=2;
i = true ? 1 : 2;
boolean
any value not false is considered true
compound boolean expressions can be used in ternary decisions
ternaries provide a format for picking immediately invoking functions
to immediately invoke a function you add parentheses after expression
function() {alert "Tim";}();
multiple actions can occur in each ternary result (but it is not suggested)
(expression == true) ? (i=1, j=2) : (i=2, j=1);
ternaries can be nested
* challenge 1.2
The above ternary conditional will assign 'no' to the adventureTime variable.
* challenge 1.3
The ternary expression above will assign 'yes' to the adventureTime variable.
* challenge 1.4
'Adventure time is now!'
* challenge 1.5
character = isHero ? 'Dhuun' : 'Pesky Gnat';
* challenge 1.6
Your new ternary expression will assign 'Dhuun' to the character variable.
* notes 1.7
LOGICAL ASSIGNMENT 1: THE "OR" OPERATOR
the OR operator "||" can be used in assignments
the first non-false value will be used
var name = inputName || 'unknown';
if the first value is used the 2nd is never evaluated
this is called a short-circuit
if no true value exists, last false value will be used
some false values are:
"", false, 0, undefined
* challenge 1.8
After this execution, the value of lost will be 4.
* challenge 1.9
Reflecting on this assignment for a bit, you realize that the undefined value will never even be examined. The name for this phenomenon in logical evaluation is called short-circuit.
* challenge 1.10
The variable lost will be set to the value of true.
* challenge 1.11
var pocketStuff = ['Dragon Tooth', 'Adventure Diary', 'Silver Tiger Coin'];
var pocketContents = pocketStuff || [];
* challenge 1.12
var pocketStuff = ['Dragon Tooth', 'Adventure Diary', 'Silver Tiger Coin'];
var cluesToThePast = pocketStuff || [];
getMyIdentity(cluesToThePast);
function getMyIdentity(memories) {
var identity = (memories.indexOf('Adventure Diary') >= 0) ? 'The One Who Learns' : undefined;
return identity || 'unknown';
}
* notes 1.13
LOGICAL ASSIGNMENT 2: THE "AND" OPERATOR
the '&&' operator uses the first false value or last true
var name = inputName && "trueValue";
the short circuit happens on first false value
some false values are:
"", false, 0, undefined
'and' is useful in contingent conditions
var knight = true;
var weapon = knight && "katana";
array.indexOf('data')
examines array and returns first occurrence of data
if the data is not found, -1 is returned
array.splice(index, numToRemove)
removes numToRemove strating at index to remove cells from the array
returns an array of removed cells
logicall assignments can be strung together
var armoryOpen = false;
var knight = true;
var weapon = knight && armoryOpen && "katana"; => would return false
* challenges 1.14
var beginJourney = aiedraIsConvincing && dhuunIsCurious;
* challenges 1.15
var surviveThisTrial = strength && !(fear);
* challenges 1.16
var strength = true;
var fear = false;
var pack = {
food: [ 'carrot',
'mystery meat',
'apple',
'crust of bread',
'spicy dried sausage',
'carrot',
'wedge of sharp cheese',
'jug of milk',
'mystery meat',
'carrot'
],
addFood: function(foodItem) {
this.food = this.food || [];
this.food.push(foodItem);
},
enoughFood: function(amount) {
return(this.food.length >= amount);
}
};
var surviveThisTrial = strength && !fear && pack.enoughFood(10);
console.log(surviveThisTrial);
* challenges 1.17
In the end, will you survive the trial at hand? (yes or no) yes
* challenges 1.18
The fear variable will short-circuit the logical assignment, and enoughFood will not be called at all.
* notes 1.19
THE SWITCH BLOCK
allows taking action on non boolean values
switch (variable) {
case 1:
food = "rabbit";
break; the keyword break exits the switch block
case 2: w/o break fall-through will continue to next case
case 3:
food = "squirrel";
break;
case 'red': can be any sort of value to check
food = "snake";
break;
default:
food = "none";
}
once a case is matched, all other cases are run
this is called fall-through unless a break statement is hit
* challenge 1.20
She said none of these.
* challenge 1.21
function aiedrasMutterings(lampsLit) {
var aiedrasWords;
switch (lampsLit) {
case 1: aiedrasWords = 'Darkness, there is so much darkness still shrouding the land.';
case 2: aiedrasWords = 'A beacon of hope, these two lamps are, but two more still await.';
case 3: aiedrasWords = 'Nearly it is complete, twilight breaking, is that a song I hear?';
case 4: aiedrasWords = 'It is done, a new age has begun, a new dawn has risen.';
default: aiedrasWords = 'Shall we live in Infinite Midnight always?';
}
return aiedrasWords;
}
alert(aiedrasMutterings(0));
* challenge 1.22
'Shall we live in Infinite Midnight always?'
* challenge 1.23
function sansTemple(direction) {
var happensNext;
switch (direction) {
case 'right hallway': happensNext = 'You find a door, it is locked. You head back from where you came.';
break;
case 'left hallway': happensNext = 'You find a door, it is locked. You head back from where you came.';
break;
case 'forward hallway': happensNext = 'You find a door, it is locked. You head back from where you came.';
break;
case 'lower tunnel': happensNext = 'You find a door, it is locked. You head back from where you came.';
break;
case 'hidden door': happensNext = 'You go through the door into a room. A small, very dark room, that smells of dust and sulfur...';
break;
default: happensNext = 'You stand there, gaping, not moving. Aiedra wonders, are you alive?';
break;
}
return happensNext;
}
sansTemple();
* challenge 1.24
function sansTemple(direction) {
var happensNext;
switch (direction) {
case 'right hallway':
case 'left hallway':
case 'forward hallway':
case 'lower tunnel': happensNext = 'You find a door, it is locked. You head back from where you came.';
break;
case 'hidden door': happensNext = 'You go through the door into a room. A small, very dark room, that smells of dust and sulfur...';
break;
default: happensNext = 'You stand there, gaping, not moving. Aiedra wonders, are you alive?';
break;
}
return happensNext;
}
sansTemple();
* challenge 1.25
function CaretakerMedallion(caretaker) {
switch (caretaker) {
case 'PixelPriest': this.bronzeBanner = 'Omne initium est a pixel';
case 'FontFriar': this.circumscribedSquare = 'Venit Comic Sans';
case 'StyleSensei': this.innerRing = 'Ars autem est in aeternum';
}
}
// Example uses of our CaretakerMedallion function
// Note the properties for each example
var medallion1 = new CaretakerMedallion('PixelPriest');
/*
CaretakerMedallion {
bronzeBanner: 'Omne initium est a pixel',
circumscribedSquare: 'Venit Comic Sans',
innerRing: 'Ars autem est in aeternum'
}
*/
var medallion2 = new CaretakerMedallion('StyleSensei');
/*
CaretakerMedallion {
innerRing: 'Ars autem est in aeternum'
}
*/
* notes 2.1
LOOP OPTIMIZATION
for loops can be optimized by removing memory access
for (var i=0; i< lilArray.length; i++)
for (var i=0, x=lilArray.length; i
* challenge 2.9
The bottom, just before the final tag.
* challenge 2.10
/* Mystical Page body html */
* challenge 2.11
JSBP
Level 2 Inverted Peninsula of Performance
Section 3 A blocking script
in our path
Inhabitants of the Inverted Peninsula, Popn:
* notes 2.12
PERFORMANCE TIPS
inheritance can help with memory efficiency
moving methods to an object prototype makes them not created for every instance
adding individual dom elements isn't always speedy
each addition to the DOM causes document reflow
use fragments to hold multiple elements that would have been used in a loop
var fragment = document.createDocumentFragment();
Declare variables as few times as possible
use commas after the var keyword
var x=1,
y=3;
Anticipate the use of variables in loops and declare before loop
concatenation efficiency
+= is the fast way to do it
except on arrays
use join method
textArray.join("\n");
* challenge 2.13
Prototypes should be used for shared properties and methods in order to increase memory efficiency.
* challenge 2.14
Use a Fragments to add conjunct elements, instead of touching the DOM over and over again.
* challenge 2.15
var list = document.getElementById('population'),
inhabitants = ['Nipping Global Variable', 'Sneaky For-in', 'Bulging Blocking Script'],
fragment = document.createDocumentFragment();
for (var i = 0, x = inhabitants.length; i < x; i++) {
var element = document.createElement('li');
element.appendChild(document.createTextNode(inhabitants[i]));
fragment.appendChild(element);
}
list.appendChild(fragment);
* challenge 2.16
Call the Array prototype's join() method on array.
* challenge 2.17
array.join(' ');
* notes 2.18
MEASURING PERFORMANCE
console.time('string'); timer is started on this string
console.timeEnd('string'); output string followed by milliseconds
multiple timers can be run at same time on different strings
averages of multiple times is needed to evaluate real time
* challenge 2.19
console.time is the opening statement to a timer method that will help us measure how long our code is taking to perform.
* challenge 2.20
true
* challenge 2.21
var array = ['Inverted Peninsula', ',', 'Inverted Peninsula', ', ', 'I', '—', 'P', '...', 'hmmm', '.'];
var internalThoughts = '';
console.time('join timer');
internalThoughts = array.join(' ');
console.timeEnd('join timer');
console.log(internalThoughts);
* challenge 2.22
var array = ['Inverted Peninsula', ',',
'Inverted Peninsula', ', ', 'I', '—',
'P', '...', 'hmmm', '.'];
var internalThoughts = '';
console.time('Test');
internalThoughts = array.join(' ');
console.time('innerTest');
console.log(internalThoughts);
console.timeEnd('innerTest');
console.timeEnd('Test');
* challenge 2.23
false
* challenge 2.24
Array.prototype.killTheInsolent = function(){};
Array.prototype.countPopulace = function(){};
Array.prototype.countUndeadPopulace = function(){};
Array.prototype.insecticide = function(){};
Array.prototype.shadowProvider = function(){};
var invertedPeninsula = {
inhabitants: ['Nipping Global Variable', 'Sneaky For-in', 'Bulging Blocking Script']
};
function populationGetter(){
var population = invertedPeninsula.inhabitants;
var list = "";
console.time('string timer');
for(var i = 0, ff = population.length; i < ff; i++){
list += (population[i] + " ");
}
console.timeEnd('string timer');
return list.trim();
}
populationGetter();
* notes 2.25
MEASURING PERFORMANCE 2
to get actual measurements you need to numerical time data
var rightNow = new Date();
to get the time in milliseconds by using a +
var rightNow = +new Date();
a speed test class can be created the will run a function and average
* challenge 2.6
var IP = ['Nipping Global Variable', 'Sneaky Forin', 'Bulging Blocking Script'],
GH = ['Switch Blocks', 'Pesky Gnat', 'Aiedra'],
inhabitants = [IP,GH];
function populationGetter(popn) {
var list = '';
for (var i = 0, x = popn.length; i < x; i++) {
for (var j = 0; j < popn[i].length; j++) {
list += (popn[i][j] + ', ');
}
}
return list;
}
populationGetter(inhabitants);
var concatTest = new SpeedTest(populationGetter, inhabitants, 100000);
concatTest.startTest();
* challenge 2.7
var IP = ['Nipping Global Variable', 'Sneaky Forin', 'Bulging Blocking Script'],
GH = ['Switch Blocks', 'Pesky Gnat', 'Aiedra'],
inhabitants = [IP,GH];
function populationGetterConcat(popn) {
var list = '';
for (var i = 0, x = popn.length; i < x; i++) {
for (var j = 0; j < popn[i].length; j++) {
list += (popn[i][j] + ', ');
}
}
return list;
}
populationGetterConcat(inhabitants);
function populationGetterJoin(popn) {
var list = [];
for (var i = 0, x = popn.length; i < x; i++) {
list.push(popn[i].join(', '));
}
return list.join(', ');
}
populationGetterJoin(inhabitants);
var concatTest = new SpeedTest(populationGetterConcat, inhabitants, 100000);
concatTest.startTest();
var joinTest = new SpeedTest(populationGetterJoin, inhabitants);
joinTest.startTest();
* notes 3.1
CAREFUL COMPARISONS
=== will compare both type and content
'4' == 4
true == 1
"\n " == 0 are true, but would be false with ===
a === ensures comparison reliability
to verify an objects class
INSTANCEOF -> returns true if the object is of that class
if (variable instanceof object)
an object is an instance of all the prototypes that it inherits properties from
* challenge 3.2
===
* challenge 3.3
Triple equals === is a safe default: it checks for matching content, as well as type.
* challenge 3.4
var strength = true;
var fear = false;
var pack = {
foodPouch: ['carrot', 'mystery meat', 'apple', 42],
addFood: function(foodItem) {
this.foodPouch = this.foodPouch || [];
this.foodPouch.push(foodItem);
},
gobbleFood: function(foodItem) {
return(this.foodPouch.indexOf(foodItem) >= 0) ?
this.foodPouch.splice(this.foodPouch.indexOf(foodItem), 1)[0] :
alert('Your pack lacks ' + foodItem);
},
feedBird: function(birdFood) {
for (var i = 0; i < this.foodPouch.length; i++) {
if (this.foodPouch[i] === birdFood) {
alert('Feed beggar bird ' + this.foodPouch[i]);
}
}
}
};
pack.feedBird('42');
* challenge 3.5
true
* challenge 3.6
myNumberNommer instanceof DatatypeBird
* challenge 3.7
function Bird(){}
function DatatypeBird(){}
function SyntaxBird(){}
DatatypeBird.prototype = Object.create(Bird.prototype);
SyntaxBird.prototype = Object.create(Bird.prototype);
var TryCatchTaster = function(){},
SwitchSnagger = function(){},
TernaryTracker = function(){};
TryCatchTaster.prototype = Object.create(SyntaxBird.prototype);
SwitchSnagger.prototype = Object.create(SyntaxBird.prototype);
TernaryTracker.prototype = Object.create(SyntaxBird.prototype);
var NumberNommer = function(){};
NumberNommer.prototype = Object.create(DatatypeBird.prototype);
var aTryCatchTaster = new TryCatchTaster();
var aSwitchSnagger = new SwitchSnagger();
var aTernaryTracker = new TernaryTracker();
var aNumberNommer = new NumberNommer();
var duneInhabitants = [aNumberNommer, aTryCatchTaster,
aSwitchSnagger, aTernaryTracker];
var count = 0;
for(var i = 0; i < duneInhabitants.length; i++) {
if (duneInhabitants[i] instanceof SyntaxBird) {
count++;
}
}
challenge 3.8
true
* challenge 3.9
Despite their differences, instances of both NumberNommer and TryCatchTaster would share the Bird as a common ancestor.
* notes 3.10
EXCEPTION HANDLING
an exception is a runtime error
try block will throw errors to catch blocks
try {
alert(alarm);
} catch (error) { error parameter is generated by try block
alert("Uh oh: " + error);
}
you can use the error type to take proper action
TypeError => wrong type of thing
ReferenceError => thing is missing
if (error instanceor ReferenceError) {
js does not pinpoint all errors
you need to use throw keyword to program your own exception
throw
if ((list instanceof Array) === false)) {
throw new TypeError();
}
when a throw statement is reached, control passes to catch
finally block
executes wether errors were found or not
try blocks can be nested
* challenge 3.11
A syntax error can be detected by the JavaScript parser before the program is ever executed, whereas a runtime error can be the result of trying to execute perfectly valid JavaScript.
* challenge 3.12
run-time
* challenge 3.13
function Bird(){}
function DatatypeBird(){}
function SyntaxBird(){}
DatatypeBird.prototype = Object.create(Bird.prototype);
SyntaxBird.prototype = Object.create(Bird.prototype);
var TryCatchTaster = function(){} ;
TryCatchTaster.prototype = Object.create(SyntaxBird.prototype);
var NumberNommer = function(){};
NumberNommer.prototype = Object.create(DatatypeBird.prototype);
* challenge 3.14
A JavaScript keyword used to identify and recover from errors is try.
* challenge 3.15
As soon as any sort of throw is reached, try passes control to catch.
* challenge 3.16
Whether errors occur or not, you can use a finally block to ensure some particular action is always taken, as long as it does not contain an error itself.
* challenge 3.17
// Pack of goods
var pack = {
foodPouch: ['carrot', 'mystery meat', 'apple', 42],
addFood: function(foodItem) {
this.foodPouch = this.foodPouch || [];
this.foodPouch.push(foodItem);
},
feedBird: function(bird) {
var food = bird.birdFood,
foodIndex = this.foodPouch.indexOf(food);
// If the exact food we want is not in the array,
// check if the type of food is there.
if (foodIndex === -1) {
throw new ReferenceError('Bird food given is not available.');
}
bird.fed = true;
}
};
// Parent Bird Class
function Bird() {}
// SyntaxBird Inherits From Parent Bird
function SyntaxBird() {}
SyntaxBird.prototype = Object.create(Bird.prototype);
var LoopLover = function(birdFood) {
this.birdFood = birdFood;
this.fed = false;
};
LoopLover.prototype = Object.create(SyntaxBird.prototype);
// DatatypeBird Inherits From Parent Bird
function DatatypeBird() {}
DatatypeBird.prototype = Object.create(Bird.prototype);
var NumberNommer = function(birdFood){
this.birdFood = birdFood;
};
NumberNommer.prototype = Object.create(DatatypeBird.prototype);
// bird variables below inherit from above prototype chain
var numba = new NumberNommer('42');
var loopy = new LoopLover('loops');
var tryCatcher = new LoopLover('la-de');
// array of all the inhabitants
var duneInhabitants = [numba, loopy, tryCatcher];
// loop through duneInhabitants and if Bird call feedBird()
for (var i = 0; i < duneInhabitants.length; i++) {
try {
pack.feedBird(duneInhabitants[i]);
} catch (error) {
console.log(duneInhabitants[i] +" was not fed.");
}
}
* notes 3.18
STUFF TO AVOID
the 'with' statement
creates a new local scope using a data container
this allows to shorten longer property names
the pitfalls are
that variable creation inside these with blocks falls outside the object
to avoid use variables for cacheing
the 'eval' statement
takes a string as a parameter and runs as a piece of code
the pitfalls are
strings that are improperly formatted can break
if used for json - code insertion code happen
try to use arrays to store data and not use eval to generate incrementing names
json data should be parsed with JSON.parse()
it is bad practice to leave off brackets on one liners
makes for bad code reading
is easy to break
can create broken code that still runs
* challenge 3.19
redundancy, scope
* challenge 3.20
// Pack of goods
var pack = {
foodPouch: ['carrot', 'mystery meat', 'apple', 42],
addFood: function(foodItem) {
this.foodPouch = this.foodPouch || [];
this.foodPouch.push(foodItem);
},
feedBird: function(birdFood) {
var food = birdFood,
foodIndex = this.foodPouch.indexOf(food);
// If the exact food we want is not in the array,
// check instead if the type of food is there.
if (foodIndex === -1) {
food = typeof food;
for (var i = 0; i < this.foodPouch.length; i++) {
if (typeof this.foodPouch[i] === food) {
foodIndex = i;
break;
}
}
}
// Check if we have the food in our pack.
if (foodIndex >= 0) {
console.log('You feed a beggar bird ' + food + '.');
this.foodPouch.splice(foodIndex, 1);
} else {
console.log('Your pack lacks ' + food + ', Dhuun.');
}
},
// Place in pack to keep your fire starting goods
fireKit: {
matchTin: {
matches: 4,
sparkPaper: 6
}
}
};
// Extra matches held outside of pack
var matches = 3;
function lightCampfire() {
var tin = pack.fireKit.matchTin
tin.matches--;
tin.sparkPaper--;
}
* challenge 3.21
var toolsForTheBug = [
{bug: 'termite', tool: 'trebuchet'},
{bug: 'slug', tool: 'sling'},
{bug: 'caterpillar', tool: 'catapult'}
];
function toolAssignment(number, tool) {
toolsForTheBug[number].tool = tool;
}
toolAssignment(1, 'Sausage');
* challenge 3.22
var tools = JSON.parse(toolsForTheBug);
* challenge 3.23
var toolsForTheBug = [
{bug: 'termite', tool: 'trebuchet'},
{bug: 'slug', tool: 'sling'},
{bug: 'caterpillar', tool: 'catapult'}
];
function toolAssignment(number, tool) {
toolsForTheBug[number].tool = tool;
}
toolAssignment(1, 'Sausage');
* notes 3.24
javascript uses binary floating point values to handle decimal operations
used for performance, but reduces accuracy
they are also not associative
toFixed() method returns numbers rounded to indicated position
var num = 0.1 + 0.2;
num.toFixed(2) = '.30'
toFixed returns a string
parseFloat() turns strings with decimals into numbers
used with toFixed it allows us to use values of exact length in other map operations
parseInt() returns the integer part of a string number
can behave bad when used with strings - NaN
can cause unexpected value errors
strings that start with 0 could be confused with octal
parseInt can take a radix number to insure proper base is found
parseInt('021', 10); should always be used
checking for numbers can be difficult
Not a Number NaN is considered a number itself
isNaN only returns true for NaN
we need to use both isNaN and typeof to guarantee
if (typeof data === "number" && !isNaN(data))
checking the value is a number and not the NaN value
form data should always be parsed before being checked for type
* challenge 3.25
var birdFeeder = {
totalFeed: 4,
getFeed: function(feedRequested) {
var returnedFeed = 0;
if (this.totalFeed >= feedRequested) {
returnedFeed = feedRequested;
this.totalFeed -= feedRequested;
} else {
returnedFeed = this.totalFeed;
this.totalFeed = 0;
}
return parseFloat(returnedFeed.toFixed(1));
},
fillFeed: function(additionalFeed) {
this.totalFeed += additionalFeed;
}
};
* challenge 3.26
parseInt(lambString, 10);
* challenge 3.27
parseFloat(lambString, 2);
* challenge 3.28
parseInt() will accept any radix value between 2 and 36 upon which to base the numerical string it has received.
If you cannot be assured of browser version, user's input, or data type, use both typeof and the function isNaN() concurrently as a best practice to ensure you are receiving numbers only.
* notes 4.1
NAMESPACING BASICS
conflicting code w/i multiple js files can cause conflicts
javascript namespaces are simulated
by using an object as a data container, we add a laywer of protection around data
this namespace object is usually capitalized
variables will become properties
ideally all incorporated js files should use a NAMESPACE
namespaces are agnostic of each other
which is useful for data protection
nested namespacing is frequent in a module pattern
* challenge 4.2
An object that groups and protects related data and methods in JavaScript files is called a namespace.
* challenge 4.3
1) overwrite, 2) globally, 3) run-time
* challenge 4.4
var CAVESYSTEM = {
stalactites: 4235,
stalagmites: 3924,
bats: 345,
treasureChests: 3,
openChest: function() {
this.treasureChests--;
alert('DA DADADA DAAAAAAA!');
}
};
* challenge 4.5
Caves of Clarity
Open the Secret Treasure!
* challenge 4.6
"A namespace ensures complete privacy of data."
Is this statement True or False? FALSE
* challenge 4.7
var CAVESOFCLARITY = {
stalactites: 4235,
stalagmites: 3924,
bats: 345,
SECRET: {
treasureChests: 3,
openChest: function() {
this.treasureChests--;
alert('DA DADADA DAAAAAAA!');
}
}
};
* challenge 4.8
Caves of Clarity
Open the Secret Treasure!
* challenge 4.9
If built well, namespaces remain AGNOSTIC of other namespaces.
If another file, with another namespace, is needed for the Caves' HTML file, the two files should not know of each other. This can aid in your data protection.
* notes 4.10
ANONYMOUS CLOSURES
public methods and values often trigger private methods and values
'closure' allows us to privatize properties
all properties are wrapped in an anonymous immediately invoked function expression (IIFE)
local values and methods are made executable
ending parentheses indicate immediate execution
it is a good habit to move all private values to top
to make properties public we create and return an object with these
var ARMORY = (function(){
var weaponList = ['sword','axe'];
var removeWeapon = function(…){};
return {
askForWeapon: function(…){}
}
})();
this will return the object as the namespace
* challenge 4.11
What feature of JavaScript is used to cause some properties to be private, bound only to a surrounding function's local scope, and some properties to be public, accessible by all holders of the namespace? closure
* challenge 4.12
Private, created, function expression, Public, object, returned, namespace, private, closure, module
* challenge 4.13
var CAVESOFCLARITY = function() {
var treasureChests = 3;
return {
stalactites: 4235,
stalagmites: 3924,
bats: 345,
SECRET: {
openChest: function() {
treasureChests--;
alert('DA DADADA DAAAAAAA!');
}
}
};
}();
* challenge 4.14
treaseChests––;
* challenge 4.15
var CAVESOFCLARITY = function() {
var treasureChests = 3,
bats = 345;
return {
stalactites: 4235,
stalagmites: 3924,
SECRET: {
openChest: function() {
treasureChests--;
alert('DA DADADA DAAAAAAA!');
}
}
};
}();
* challenge 4.16
Since it's never accessed through the public methods, the private bats datum holds no functional purpose.
* challenge 4.17
var CAVESOFCLARITY = function() {
var treasureChests = 3;
var bats = 345;
return {
stalactites: 4235,
stalagmites: 3924,
SECRET: {
openChest: function() {
treasureChests--;
alert('DA DADADA DAAAAAAA!');
}
},
getBats: function() {
return(bats);
}
};
}();
* challenge 4.18
The parentheses that immediately invoke the function.
* notes 4.19
GLOBAL IMPORTS
global variables used inside a namespace makes searching the entire scope change to find global
developers will have a hard time tracing because of unclear scope
global variables can get accidentally change
for clearer, faster globals use imports
add a parameter to the wrapper immediately invoked function
change globals in namespace to new parameter
pass in globals into IIFE using calling expressions
variable is closed as a local value
global stays protected
* challenge 4.20
If a module references globally-scoped variables, it's a best practice to bring them into the scope of anonymous closure through the use of a specific technique.
What is the name for this? Global Import
* challenge 4.21
var LEXICALLAKE = (function(answer) {
var depth = 400;
var fish = 1200;
var unknownSleepers = 3;
return {
getFish: function() { return fish; },
getDepth: function() { return depth; },
getSleepers: function() {return unknownSleepers; },
awakenSleeper: function() {
alert('Far below, in the deep, something awakens. Row faster.');
},
summonBoat: function() {
if (answer === 'agnostic') {
alert('The boat fades into view.');
}
else {
alert('...the lake is silent.');
}
}
};
})(explorerAnswer);
* challenge 4.22
Your import ensures clarity of scope within a module.
By using a parameter, you protect the global data that might have been overwritten.
All imported data becomes locallu scoped to the anonymous function, to be used in closure.
Thus, when compared with searching the entire scope chain, imports are both clearer and faster.
* challenge 4.23
var LEXICALLAKE = (function(answer, foundShore) {
var depth = 400;
var fish = 1200;
var unknownSleepers = 3;
return {
getFish: function() { return fish; },
getDepth: function() { return depth; },
getSleepers: function() { return unknownSleepers; },
awakenSleeper: function() {
alert('Far below, in the deep, something awakens. Row faster.');
},
summonBoat: function() {
if (answer === 'agnostic') {
alert('The boat fades into view.');
}
else {
alert('...the lake is silent.');
}
},
stopSleeper: function() {
if (foundShore) {
alert('That which has awoken shall now return to slumber.');
}
else {
alert('A Sleeper cometh. Abandon hope.');
}
}
};
})(explorerAnswer, madeItAcross);
* notes 4.24
AUGENTATION
when updating or adding additions to a module it is often better to separate into files
augmentation is using a separate file to add functionality to a module
in a separate file we build a namespace with same namespace
we import the old namespace via last lesson
we get a new object with added functionality
new functions do not get to see closed data in original namespace
group file contents around related data
* challenge 4.25
What is the term for adding or changing properties in a module after the module has already been built? Augmentation
* challenge 4.26
CAVESOFCLARITY = (function(caves) {
var sandScript = '';
caves.setSandScript = function(message) {
sandScript = message;
};
return caves;
})(CAVESOFCLARITY);
* challenge 4.27
In simple augmentation, the module file and the augmentation file do not share their private state.
Augmented module properties may only access the private data from their file's closure.
Private data from the original closure will not be lost, and will be accessible to all original properties that referenced it.