lahdiouiouadie
ouadie-lahdioui
Charles Bihis - Computer Scientist at Adobe Systems
@charlesbihis
github.com/charlesbihis
We will deal with only pure JavaScript (No 3rd partyl libraries or framworks)
We are going to talk about :
A puzzler is a very simple program that demonstrates or exploits weird behaviours and quirky edge-cases of a given programming language
I introduce the code, I pose a multiple-choice question and you guess what the answer is ... think hard !
Walkthrought : I walk through a reasonable explanation
Answer : I tell you the real answer
Moral : How can you avoid making mistakes line in your own code
var commonusRule = 'thumbsUp';
console.log('Maximus the' + (commonusRule === 'thumbsUp') ? 'Gladiator' : 'Merciful');
What does this print ?
A) Maximus the Gladiator
B) Maximus the Merciful
C) Error
D) It varies
E) None of the above
Print only Gladiator
Order of operations dictates that the binary '+' operator takes precedence over the conditional '?' operator
var commonusRule = 'thumbsUp';
console.log('Maximus the' + (commonusRule === 'thumbsUp') ? 'Gladiator' : 'Merciful');
'Maximus the true' ? 'Gladiator' : 'Merciful';
var commonusRule = 'thumbsUp';
console.log('Maximus the' + (commonusRule === 'thumbsUp' ? 'Gladiator' : 'Merciful'));
var commonusRule = 'thumbsUp';
console.log('Maximus the' + (commonusRule === 'thumbsUp') ? 'Gladiator' : 'Merciful');
Old :
New :
// Global var
var name = 'World!';
(function() {
// Check if 'name' defined
if (typeof name === 'undefined') {
// local "shadow" var
var name = 'Mr. Bond.';
console.log('Goodbye, ' + name);
} else {
console.log('Hello, ' + name);
}
})();
A) 'Hello, World!'
B) 'Goodbye, Mr.Bond.'
C) 'Hello,'
D) 'Hello, undefined'
E) Error
F) It varies
G) Non of the above
What does this print ?
No block scope !
Hoisting
for (var i = 0; i < MAX; i++) {
// do something
}
console.log(i); // Note: 'i' exists here !
console.log(i); // Note: 'i' exists here too !
for (var i = 0; i < MAX; i++) {
// do something
}
var i;
// Global var
var name = 'World!';
(function() {
var name; // declaration hoisted here
// Check if 'name' defined
if (typeof name === 'undefined') {
name = 'Mr. Bond.'; // assignment remains here
console.log('Goodbye, ' + name);
} else {
console.log('Hello, ' + name);
}
})();
// Global var
var name = 'World!';
(function() {
// Check if 'name' defined
if (typeof name === 'undefined') {
// local "shadow" var
var name = 'Mr. Bond.';
console.log('Goodbye, ' + name);
} else {
console.log('Hello, ' + name);
}
})();
Old :
New :
var zipCodes = new Array('15','015', 015, '0X15');
// let's display each zip-code
for (var i = 0; i < zipCodes.length; i++) {
// sanity check
if (!isNaN(parseInt(zipCodes[i])) &&
parseInt(zipCodes[i]) > 0) {
console.log(parseInt(zipCodes[i]));
}
}
What does this print ?
B) 15
15
13
21
C) 15
015
15
D) Error
E) It varies
F) None of the above
A) 15
015
15
Nan
parseInt(string, radix);
If radix is undefined, 0 or absent, JS assumes the following:
A closer look ...
parseInt('15') = 15
parseInt(15) = 15
parseInt(015) = 13
parseInt(0x15) = 21
// it's another zipCodes
var zipCodes = new Array('93021','02392','20341','08163','32959');
// let's display each zip-code
for (var i = 0; i < zipCodes.length; i++) {
// sanity check
if (!isNaN(parseInt(zipCodes[i], 10)) && // radix value added
parseInt(zipCodes[i], 10) > 0) { // here too
console.log(parseInt(zipCodes[i], 10)); // and here too
}
}
// it's another zipCodes
var zipCodes = new Array('93021','02392','20341','08163','32959');
// let's display each zip-code
for (var i = 0; i < zipCodes.length; i++) {
// sanity check
if (!isNaN(parseInt(zipCodes[i])) &&
parseInt(zipCodes[i]) > 0) {
console.log(parseInt(zipCodes[i]));
}
}
Old :
New :
var END = 9007199254740992; // Math.pow(2, 53)
var START = END - 100;
var count = 0;
for (var i = START; i <= END; i++) {
count++;
}
console.log(count);
What does this print ?
A) 0
B) 100
C) 101
D) Error
E) It varies
F) None of the above
Enters infinite loop
var numA = Math.pow(2, 53);
var numB = numA + 1;
console.log(numA === numB);
var END = 9007199254740992; // Math.pow(2, 53)
var START = END - 100;
var count = 0;
for (var i = START; i <= END; i++) {
count++;
}
console.log(count);
var END = 100;
var START = 0;
var count = 0;
for (var i = START; i <= END; i++) {
count++;
}
console.log(count);
Old :
New :
var costOfCandy = 0.60; // 60 cents
function calculateChange(cost, paid) {
return paid - cost;
}
// pay fod candy with 80 cents
console.log(calculateChange(costOfCandy, 0.80))
A) 0
B) 0.2
C) 0.20
D) None of the above
What does this print ?
0.20000000000000007
123.45 = 12345 * 10^2 // exact
1/3 = 0.3333333333333333 // approximation
var costOfCandy = 0.60; // 60 cents
function calculateChange(cost, paid) {
return paid - cost;
}
// pay fod candy with 80 cents
console.log(calculateChange(costOfCandy, 0.80))
var costOfCandy = 60;
function calculateChange(cost, paid) {
return paid - cost;
}
// pay fod candy with 80 cents
console.log(calculateChange(costOfCandy, 80))
Use only integer math when dealing with money : 60 instead of 0.60 to represent 0.60 cents
Old :
New :
function showCase(value) {
switch(value) {
case "A":
console.log("Case A was selected.");
break;
case "B":
console.log("Case B was selected.");
break;
case "C":
console.log("Case C was selected.");
break;
default
console.log("Don't know what happened.");
break;
}
}
showCase(new String("A"));
A) Case A was selected.
B) Case B was selected.
C) Case C was selected.
D) Don't know what happened.
E) Error
F) None of the above
What does this print ?
console.log(typeof 'A') // string
console.log(typeof new String('A')) // object
function showCase(value) {
switch(value) {
case "A":
console.log("Case A was selected.");
break;
case "B":
console.log("Case B was selected.");
break;
case "C":
console.log("Case C was selected.");
break;
default
console.log("Don't know what happened.");
break;
}
}
// showCase(new String("A"));
showCase("A");
function showCase(value) {
switch(value) {
case "A":
console.log("Case A was selected.");
break;
case "B":
console.log("Case B was selected.");
break;
case "C":
console.log("Case C was selected.");
break;
default
console.log("Don't know what happened.");
break;
}
}
showCase(new String("A"));
Old :
New :
JavaScript has two sets of equality operators: === and !==, and their evil twins == and !=.
The good ones work the way you would expect. The evil twins do the right thing when the operands are of the same type, but if they are of different types, they attempt to coerce the values.
lahdiouiouadie
ouadie-lahdioui