Skip to content

Instantly share code, notes, and snippets.

@elgalu
Created September 4, 2013 23:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save elgalu/6444051 to your computer and use it in GitHub Desktop.
Save elgalu/6444051 to your computer and use it in GitHub Desktop.
A Drip of JavaScript - book notes / quizzes
// 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