Upload
trancong
View
215
Download
2
Embed Size (px)
Citation preview
Functionals• Javascript functions are first class objects
o Can be passed as arguments to a functiono Can be returned from a functiono Can be assigned to a variableo Can be stored in an object or array
• Functionalso Functions that take functions as an argumento Can be used to capture common idioms
• Exampleso Generators/iteratorso List functionals: map, reduce, filter, etc.
Javascript Arrays• Javascript operations
o pusho unshifto popo shifto spliceo concat
• Autofillingo If set at index beyond length, the elements in
between are set to undefined o If the value not specified in declaration, it is also set
to undefined
> a = [3,5,7][3, 5, 7]> a.push(9)4> a[3, 5, 7, 9]> a.unshift(1)5> a[1, 3, 5, 7, 9]> a.pop()9> a[1, 3, 5, 7]> a.shift()1> a[3, 5, 7]> a.splice(1,1,6)[5]> a[3, 6, 7]> a[4] = 88> a[3, 6, 7, undefined, 8]> a = [3, ,7] > a [3, undefined, 7]
Generators/Iterators• Common idiom – iterating over a set of elements
• Generators in Pythono Useful feature
• What about Javascript?
>>> def elements(a):... for i in range(0, len(a)): ... yield a[i]>>> for e in elements ([1,2,3]):... print e12
a = [1, 2, 3];for (var i = 0; i < a.length; i++) {
// do something with a[i]}
Generators/Iteratorsvar forEach = function(a) {
return function(body) {for (var i = 0; i < a.length; i++) {
body(a[i]);}
}}
> var a = [1, 2, 3]> var printSquare = function(x) { console.log(x*x); }> var iteratea = forEach(a);> iteratea(printSquare);149> a = [4, 5, 6]; > iteratea(printSquare);149> forEach(a)(printSquare);162536
body is a function
> iterateafunction(body) {
for (var i = 0; i < a.length; i++) {body(a[i]);
}}
Array methods• Can make functionals methods
o Add as properties to Array.prototype
var forEach = function(a) { return function(body) {
for (var i = 0; i < a.length; i++) {body(a[i]);
}}
}
Array.prototype.forEach = function(body) {for (var i = 0; i < this.length; i++) {
body(this[i]);}
}
var sum = function (a) {var result = 0;a.forEach(function (e) {
result += e;});return result;
}
> sum([1,2,3])6
> var a = [1, 2, 3]> var printSquare = function(x) {
console.log(x*x); }> a.forEach(printSquares)149
Bef
ore
Afte
r
Map
• type› map: list[A] x (A→B) → list[B]
Array.prototype.map = function (f) {var result = [];this.forEach (function (e) {
result.push(f(e));});return result;
}
> var square = function (x) { return x * x; }> var a = [1, 2, 3]; > a.map(square)[1, 4, 9]
Reduce
• Also known as fold• type› reduce: list[A] x (A x B→B) x B → B • Sum with reduce?
Array.prototype.reduce = function (f, base) {var result = base;this.forEach (function (e) {
result = f(e, result);});return result;
}
> var times = function (x, y) { return x * y; }> var a = [1, 2, 3]; > a.reduce(times, 1)6> var add = function (x, y) { return x + y; }> a.reduce(add, 0)6
Filter
• type› filter: list[A] x (A→Bool) → list[A]
• Can combine different operations
Array.prototype.filter = function (p) {var result = [];this.forEach (function (e) {
if (p(e)) result.push(e);});return result;
}
> var a = [1, 2, 3, 4, 5]; > a.filter (function (e) {return e > 2; }) [3, 4, 5]> a.filter (function (e) {return e > 2; }).map(square) [9, 16, 25]
Contains?
• Does this work?• Early returns are a problem
Array.prototype.contains = function (e) {this.forEach(function (x) {
if (x === e) return true;});return false;
}
> var a = [1, 2, 3]; > a.contains(1)false
Contains?
• Reduce to the rescue…• Still have to process allelements
Array.prototype.contains = function (e) {var f = function (x, found) {
return found || (x === e);}return this.reduce(f, false);
}
> var a = [1, 2, 3]; > a.contains(1)true
Closure Example• Fibonacci
var fib = function (i) {if (i < 2) return 1;return fib(i‐1) + fib(i‐2);
}
> console.time('fib'); > fib(20); > console.timeEnd('fib');fib: 7ms> console.time('fib'); > fib(34); > console.timeEnd('fib');fib: 5737ms> console.time('fib'); > fib(35); > console.timeEnd('fib');fib: 9335ms
Memoizationvar memoize = function (f) {
var memo = [];return function (i) {
if (memo[i] === undefined) memo[i] = f(i);
return memo[i];}
}
var mfib = memoize(function (i) {console.log(i);if (i < 2) return 1;return mfib(i‐1) + mfib(i‐2);
});
> mfib(5)5432108> mfib(10)10987689
Memoizationvar memoize = function (f) {
var memo = [];return function (i) {
if (memo[i] === undefined) memo[i] = f(i);
return memo[i];}
}
var mfib = memoize(function (i) {if (i < 2) return 1;return mfib(i‐1) + mfib(i‐2);
}); > console.time('fib'); > fib(35); > console.timeEnd('fib');fib: 9335ms> console.time(‘mfib'); > mfib(35); > console.timeEnd(‘mfib');fib: 1ms> console.time(‘mfib'); > mfib(1000); > console.timeEnd(‘mfib');fib: 3ms
Walking the DOM Treevar walk = function (elt, f) {
f(elt);var child = elt.firstElementChild;while (child) {
walk(child, f);child = child.nextElementSibling;
}}
var filter = function(elt, f) {var result = [];walk(elt, function (x) {
if (f(x)) result.push(x);});return result;
}
> filter(document.body, function (e) { return e.tagName === 'DIV'; })
Walking the DOM TreeElement.prototype.forEach = function (f) {
f(this);var child = this.firstElementChild;while (child) {
child.forEach(f);child = child.nextElementSibling;
}}
var filter = function(a, f) {var result = [];a.forEach(function (x) {
if (f(x)) result.push(x);});return result;
}
> filter(document.body, function (e) { return e.tagName === 'DIV'; })
Walking the DOM Treefunction walk(elt, meta_parent) {
var meta_elt = make_meta(elt, meta_parent);var child = elt.firstElementChild;while (child) {
walk(child, meta_elt);child = child.nextElementSibling;
} }
var walk = function(elt, f, meta_parent) {var meta_elt = f(elt);meta_parent.appendChild (meta_elt);var child = elt.firstElementChild;while (child) {
walk(child, f, meta_elt);child = child.nextElementSibling;
}return parent;
};
Bef
ore
Afte
r
Walking the DOM Treefunction walk(elt, meta_parent) {
var meta_elt = make_meta(elt, meta_parent);var child = elt.firstElementChild;while (child) {
walk(child, meta_elt);child = child.nextElementSibling;
} }
var walk = function(elt, f, meta_parent) {var meta_elt = f(elt);meta_parent.appendChild (meta_elt);var child = elt.firstElementChild;while (child) {
walk(child, f, meta_elt);child = child.nextElementSibling;
}return parent;
};
function make_meta(elt, meta_parent) {var meta_elt = make_matching_element(elt); var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover",
function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});
meta_elt.addEventListener("mouseout", function () {
elt.style.backgroundColor = original_color;});meta_parent.appendChild (meta_elt);return meta_elt;
}
function make_meta(elt, meta_parent) {var meta_elt = make_matching_element(elt); var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover",
function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});
meta_elt.addEventListener("mouseout", function () {
elt.style.backgroundColor = original_color;});meta_parent.appendChild (meta_elt);return meta_elt;
}
function make_meta(elt, meta_parent) {var meta_elt = make_matching_element(elt); var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover",
function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});
meta_elt.addEventListener("mouseout", function () {
elt.style.backgroundColor = original_color;});meta_parent.appendChild (meta_elt);return meta_elt;
}
Bef
ore
Afte
r
Walking the DOM Treefunction walk(elt, meta_parent) {
var meta_elt = make_meta(elt, meta_parent);var child = elt.firstElementChild;while (child) {
walk(child, meta_elt);child = child.nextElementSibling;
} }
var walk = function(elt, f, meta_parent) {var meta_elt = f(elt);meta_parent.appendChild (meta_elt);var child = elt.firstElementChild;while (child) {
walk(child, f, meta_elt);child = child.nextElementSibling;
}return parent;
};
function make_meta(elt, meta_parent) {var meta_elt = make_matching_element(elt); var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover",
function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});
meta_elt.addEventListener("mouseout", function () {
elt.style.backgroundColor = original_color;});meta_parent.appendChild (meta_elt);return meta_elt;
}
function make_meta(elt, meta_parent) {var meta_elt = make_matching_element(elt); var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover",
function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});
meta_elt.addEventListener("mouseout", function () {
elt.style.backgroundColor = original_color;});meta_parent.appendChild (meta_elt);return meta_elt;
}
function make_meta(elt, meta_parent) {var meta_elt = make_matching_element(elt); var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover",
function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});
meta_elt.addEventListener("mouseout", function () {
elt.style.backgroundColor = original_color;});meta_parent.appendChild (meta_elt);return meta_elt;
}
function make_meta(elt) {var meta_elt = make_matching_element(elt); var original_color = elt.style.backgroundColor;meta_elt.addEventListener("mouseover",
function (event) {event.stopPropagation();elt.style.backgroundColor = "yellow";});
meta_elt.addEventListener("mouseout", function () {
elt.style.backgroundColor = original_color;});
return meta_elt; }
Bef
ore
Afte
r
Walking the DOM Treefunction walk_body() {
var body = document.body;var fragment = document.createDocumentFragment();walk(body, fragment);body.insertBefore(make_scroll_box(fragment), body.firstChild);
}
var walk_body = function () {var body = document.body;var fragment = document.createDocumentFragment();walk(body, make_meta, fragment);body.insertBefore(make_scroll_box(fragment), body.firstChild);
}
Bef
ore
Afte
r
Another approachvar walk = function(elt, f, meta_parent) {
var mf = memoize(function(e) {if (e === elt.parentElement)
return meta_parent;return f(e);
});
elt.forEach(function (e) { mf(e.parentElement).appendChild (mf(e));
});};
var memoize = function (f) {var memo = [];return function (e) {
if (memo[e.uid()] === undefined) memo[e.uid()] = f(e);
return memo[e.uid()];}
}
Element.prototype.uid = (function () {var count = 0;return function () {
var id = count++;this.uid = function () { return id; }return id;
} })();
Generates a unique element id foreach element
mf: Apply f to each element e if you haven’t already and store the result.
Applies f to each element e and builds the new tree.