Created
September 4, 2013 23:10
-
-
Save elgalu/6444051 to your computer and use it in GitHub Desktop.
A Drip of JavaScript - book notes / quizzes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Explain what the Function.prototype.bind method allows. | |
// Use properly to fix this TypeError: Illegal invocation | |
var myLog = console.log; | |
myLog("hola"); | |
=> | |
// The bind method allows us to create a new function which is permanently bound to a given value of `this` | |
var myLog = console.log.bind(console); | |
myLog("hola"); //==> "hola" | |
// As a bonus, you can't override its `this` value using call or apply. | |
myLog.call(window, "hello"); // will be ignored and will keep bound to console.log() | |
// Remember on IE <= 8 you'll need es5-shim.js | |
// 1. What does it means that in Javascript variables and functions are "hoisted" | |
// 2. Returns? | |
console.log(j); //=> ? | |
var j = 3; | |
console.log(j); //=> ? | |
// 3. What about function hoisting? | |
isItHoisted(); //=> ? | |
function isItHoisted() { | |
console.log("Yes!"); | |
} | |
=> | |
// 1. It means that rather than being available after their declaration, | |
// they might actually be available beforehand | |
console.log(j); //=> undefined | |
var j = 3; | |
console.log(j); //=> 3 | |
// If no `var j` would be available in the script then the result would have been different: | |
console.log(j); //=> ReferenceError: j is not defined | |
// So please put all variable declarations at the top of the functions to avoid this pitfalls. | |
// 3. JS will look ahead and execute the correct function | |
isItHoisted(); //==> "Yes!" | |
// Note function definition hoisting only occurs for function declarations, not function expressions | |
definitionHoisted(); //==> "Definition hoisted!" | |
definitionNotHoisted(); //==> TypeError: undefined is not a function | |
funcName(); //==> ReferenceError: funcName is not defined | |
varName(); //==> TypeError: undefined is not a function | |
function definitionHoisted() { | |
console.log("Definition hoisted!"); | |
}; | |
var definitionNotHoisted = function () { | |
console.log("Definition not hoisted!") | |
}; | |
var varName = function funcName() { | |
console.log("Definition not hoisted!") | |
}; | |
// Diff bt `hasOwnProperty` vs `in` | |
var leo = { slug: 'elgalu', age: 32 }; | |
=> | |
// Both looks for properties | |
"slug" in leo; //=> true | |
leo.hasOwnProperty("slug"); //=> true | |
// Diff is how they handle properties inherited from prototype chain: | |
"constructor" in leo; //=> true | |
leo.hasOwnProperty("constructor"); //=> false | |
// In JS. Can you assign a new value to `undefined` ? | |
undefined = "my string"; | |
console.log(undefined); //=> ? | |
=> | |
// It depends on which version of ECMAScript. | |
// For ES3 engines (like IE8 & below) | |
"my string" is logged | |
// For ES5 engines, it silently prevents new values to be assigned to undefined | |
// In ES5's strict mode will fail with an error | |
"use strict"; | |
undefined = "my string"; | |
// Map this array of numbers into an array of square roots using Array.prototype.map() | |
var nums = [1, 4, 9]; | |
var roots = ??? //=> [1, 2, 3] | |
=> | |
var roots = nums.map(Math.sqrt); //=> [1, 2, 3] | |
// Fix the following problem | |
var ary = ["1", "2", "3"]; | |
ary.map(parseInt); //=> [1, NaN, NaN] | |
=> | |
function returnInt(el) { | |
return parseInt(el, 10); | |
} | |
ary.map(returnInt); //=> [1, 2, 3] | |
// Or the one-liner: | |
ary.map( function(el) { return parseInt(el, 10); } ); | |
// What are the JS ways to merge the contents of two or more objects together into the first object? | |
var obj1 = { name: 'leo', age: 32 }; | |
var obj2 = { slug: 'elgalu' }; | |
// Tip: In ruby that would be: | |
obj1.merge!(obj2) //==> Object {name: "leo", age: 32, slug: "elgalu"} | |
=> | |
// Using jQuery or Underscore.js | |
$.extend(obj1, obj2); | |
// The following preserves the original objects: | |
var obj3 = $.extend({}, obj1, obj2); | |
var obj3 = _.extend(obj1, obj2); | |
// Is there a way, within a function, to get access to all of the arguments that were | |
// supplied with the function invocation? | |
// Including excess arguments that were not assigned to parameters? | |
=> | |
// Yes, yes. Using the `arguments` pseudo-array | |
arguments | |
// Returns? | |
var ary = [3, 4, 5, 6]; | |
ary.slice(1, 3); //=> ? | |
ary.slice(1); //=> ? | |
ary.slice(); //=> ? | |
=> | |
// Array.slice(begin[, end]) | |
ary.slice(1, 3); //=> [4, 5] | |
ary.slice(1); //=> [4, 5, 6] | |
// begin defaults to 0 and end to ary.length | |
ary.slice(); //=> [3, 4, 5, 6] | |
// What are the dangers of invoking a constructor without `new` ? | |
function Color(r, g, b) { | |
this.r = r; this.g = g; this.b = b; | |
} | |
blue = Color(0, 0, 255); | |
=> | |
// The problem is that the value of `this` will be the global object which is `window` within a Browser. | |
// Using `new` provides the safe invocation: | |
red = new Color(255, 0, 0); | |
// That problem can be avoided using the following technique | |
function Color(r, g, b) { | |
if (this instanceof Color) { | |
this.r = r; this.g = g; this.b = b; | |
} else { | |
throw new Error("`Color` invoked without `new`"); | |
} | |
} | |
// Given the following | |
function Book(title, author) { | |
this.title = title; | |
this.author = author; | |
} | |
Book.prototype.pubYear = "idk"; | |
var hobbit = new Book("The Hobbit", "Tolkien"); | |
var caspian = new Book("Prince Caspian", "Lewis"); | |
caspian.pubYear = 1951; | |
// Returns? | |
hobbit.pubYear; //=> ? | |
caspian.pubYear; //=> ? | |
Book.prototype.pubYear; //=> ? | |
=> | |
// JS will search for pubYear within the prototype chain | |
hobbit.pubYear; //=> "idk" | |
caspian.pubYear; //=> 1951 | |
Book.prototype.pubYear; //=> "idk" | |
// What advantages can present this | |
function Pixel1(x, y) { | |
this.x = x; this.y = y; | |
this.distance = function() { return Math.pow(this.x, this.y); }; | |
} | |
// Over this | |
function Pixel2(x, y) { | |
this.x = x; this.y = y; | |
} | |
Pixel2.prototype.distance = function() { return Math.pow(this.x, this.y); }; | |
// Given it will be used like this | |
(new Pixel1(2,3)).distance(); //=> 8 | |
(new Pixel2(2,3)).distance(); //=> 8 | |
=> | |
// Adding distance() within the prototype makes the function available to | |
// all Pixel objects, present and future ones and will additionally save memory. | |
// Improve the following code readiness by using a dispatch table pattern. | |
// Why? Because sometimes is nice to avoid conditionals. | |
function processUserInput(command) { | |
switch (command) { | |
case "north": | |
movePlayer("north"); break; | |
case "east": | |
movePlayer("east"); break; | |
case "look": | |
describeLocation(); break; | |
case "backpack": | |
showBackpack(); break; | |
} | |
}= | |
=> | |
var commandTable = { | |
north: function() { movePlayer("north"); }, | |
east: function() { movePlayer("east"); }, | |
look: describeLocation, | |
backpack: showBackpack | |
} | |
function processUserInput(command) { | |
commandTable[command](); | |
} | |
// Explain the following ES5 method | |
ary.some(callback[, thisObject]) | |
=> | |
// Tests whether some element in the array passes the test implemented by the provided function. | |
ary // an Array | |
callback // Function to test for each element. | |
thisObject // Object to use as `this` when executing callback. | |
// It is equivalent to Ruby's Enumerable#any? | |
```ruby | |
%w[ant bear cat].any? { |word| word.length >= 4 } #=> true | |
``` | |
// In computer science, partial application refers to the process of fixating a | |
// number of arguments to a function producing another function of smaller arity. | |
// Provide an example of using it within JS | |
=> | |
function multiply (a, b) { return a * b; } | |
function timesCreator (a) { | |
return function (b) { | |
return multiply(a, b); | |
} | |
} | |
// To achieve 2 separate functions of arity 1 by using partial application | |
timesCreator(2)(3); //=> 6 | |
// Underscore.js provides an utility to achieve partial application | |
// allowing the arguments to be binded (saved within a closure) | |
_.bind(function, object, [*arguments]) | |
// Given | |
function Color (r, g, b) { | |
this.r = r; this.g = g; this.b = b; | |
} | |
var red = new Color(255, 0, 0); | |
alert(red); //=> "[object Object]" | |
// Improve that alert into: | |
"rgb(255, 0, 0)" | |
=> | |
// Overriding default's toString will do. | |
// This is somehow the equivalent to overriding Ruby's String#to_s | |
Color.prototype.toString = function () { | |
return "rgb(" + this.r + ", " + this.g + ", " + this.b + ")"; | |
}; | |
// Diff bt call() vs apply() | |
=> | |
// Both are methods invokation that set the value of `this` within the first argument | |
// The diff is that Function.prototype.apply takes an array of arguments | |
// while Function.prototype.call takes them separately: | |
func.apply(valueForThis, arrayOfArgs); | |
func.call( valueForThis, arg1, arg2, ...); | |
// Mnemonic: "a => apply => array" | |
// 1. In ES6, does this operator `...` has a name? | |
var someArgs = ["a", "b", "c"]; | |
console.log(...someArgs); | |
// 2. How is it implemented in CoffeeScript? | |
=> | |
// Yes, the spread operator. | |
// In Ruby is `*` instead of `...` and is called the splat operator. | |
// In CoffeeScript is `...` like in ES6 but must be appended at the end: | |
console.log(someArgs...); | |
// The operator allows you to switch between parameters and arrays. | |
// The operator works in both ways, it splits a list in a series of parameters, | |
// or collects a series of parameters to fill an array. | |
// Explain | |
Array.prototype.concat | |
=> | |
array.concat(value1, value2, ..., valueN) | |
// Creates a **new** array consisting of the elements in the this object on which | |
// it is called, followed in order by, for each argument, | |
// the elements of that argument (if the argument is an array) | |
// or the argument itself (if the argument is not an array). | |
// The Ruby most similar equivalent is Array#concat but only works with Arrays | |
// so in Ruby you would need to work it on using Array() constructor | |
```ruby | |
ary = [1, 2] | |
ary.concat(Array([3]).concat(Array(4))) #=> [1, 2, 3, 4] | |
# Note ary is updated by concat | |
ary #=> [1, 2, 3, 4] | |
%w(a b).concat(Array(%w(c d))) #=> ["a", "b", "c", "d"] | |
# To avoid this you can use Array#+ combined with Array() when necessary | |
ary + [5, 6] #=> [1, 2, 3, 4, 5, 6] | |
ary #=> [1, 2, 3, 4] | |
``` | |
// Returns? | |
[1, 2, 3].reduce(function(prev, curr, index, arr) { | |
console.log(prev, curr, index); | |
return prev + curr; | |
}, 100); | |
=> | |
//==> 100 1 0 | |
//==> 101 2 1 | |
//==> 103 3 2 | |
//=> 106 | |
// In Ruby, Enumerable#all? accepts a block and returns true if the block | |
// never returns false or nil. If the block is not given, an implicit | |
// { |obj| obj } is provided by the language, e.g. | |
```ruby | |
%w[ant bear cat].all? { |word| word.length >= 3 } #=> true | |
``` | |
// Is there an equivalent method in JS? | |
=> | |
// Yes, ES5 Array.prototype.every | |
array.every(callback[, thisObject]) | |
// What error JS is thrown out of | |
42.toString(); //==> ? | |
9.75.toString(); //==> ? | |
// How can be fixed? | |
=> | |
// Error due to JS expecting a float after the dot `.` | |
42.toString(); //==> SyntaxError: Unexpected token ILLEGAL | |
// No error with explicit floats | |
9.75.toString(); //=> "9.75" | |
// Several ways to fix it: | |
(42).toString(); //=> "42" | |
42.0.toString(); //=> "42" | |
42..toString(); //=> "42" | |
42 .toString(); //=> "42" | |
42['toString'](); //=> "42" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment