shaman.sir, Animatron, 2012
Mastering Functional
JavaScript
(the super-duper lecture that will let you win in the end)
(especially if you will be a smart guy)
Slide 2
Slide 2 text
?
(you are just silent in the absence of thoughts and don't know what to ask)
(so I'l tell you which way the lecture will go)
About me.
Structure of a function.
Lambdas.
Named functions.
In-place call.
this.
call & apply.
Common pitfalls and tricks.
Deferred functions.
Partial applications.
Queueing functions.
Iterators & Generators.
Composing functions.
Objects from a functions' view.
Slide 3
Slide 3 text
Who's that guy?
(means me)
I am shaman.sir,
a.k.a. Kotenko Anton,
experienced JavaScript web developer.
You may find my homesite at http://shamansir.github.com,
and my blog is at http://shamansir.github.com/blog;
my e-mail is [email protected].
Slide 4
Slide 4 text
What is a Function?
So,..
Slide 5
Slide 5 text
What is a Function?
arguments
body
result
value
Slide 6
Slide 6 text
Which way it looks like
in JavaScript?
function(x, y, z) { return ω; }
Slide 7
Slide 7 text
Factually, this example itself
is a lambda (λ), an in-place
function without a name...
function(x, y, z) { return ω; }
Slide 8
Slide 8 text
Factually, this example itself
is a lambda (λ), an in-place
function without a name...
function(x, y, z) { return ω; }
Slide 9
Slide 9 text
Here are several named
(instead) variants...
var foo = function(x, y, z) { return ω; }
function foo(x, y, z) { return ω; }
bar.foo = function(x, y, z) { return ω; }
bar.prototype.foo = function(x, y, z) { return ω; }
Slide 10
Slide 10 text
Here are several named
(instead) variants...
var foo = function(x, y, z) { return ω; }
function foo(x, y, z) { return ω; }
bar.foo = function(x, y, z) { return ω; }
bar.prototype.foo = function(x, y, z) { return ω; }
Slide 11
Slide 11 text
...And how d'ya call them.
foo(x, y, z);
foo(x, y, z);
bar.foo(x, y, z);
new bar().foo(x, y, z);
Slide 12
Slide 12 text
...And how d'ya call them.
var a = foo(x, y, z);
var a = foo(x, y, z);
var a = bar.foo(x, y, z);
var a = new bar().foo(x, y, z);
Slide 13
Slide 13 text
Using lambda format, you
may pass one function to
any other function
Slide 14
Slide 14 text
Using lambda format, you
may pass one function to
any other function
function(x, y, z) { return ω; }
function filter(xs, f) { ... f(xs[i]) ... }
filter([...], function(x, y, z) { return ω; });
Slide 15
Slide 15 text
You may call lambda
in-place
(function(x, y, z) { return ω; })(25, 6, 11)
with passing actual values
Slide 16
Slide 16 text
You may call lambda
in-place
(function(x, y, z) { return x+y+z; })(25, 6, 11)
with passing actual values
➟ 42
Slide 17
Slide 17 text
You may return function
from lambda and call it then
Slide 18
Slide 18 text
You may return function
from lambda and call it then
(function(z, a, b) {
var x = a + b;
return function(y) {
return x + y + z;
};
})(11, 20, 5)(6); ➟ 42
Slide 19
Slide 19 text
Any function may be called
with particular this state
var foo = function(z) { return this.x+this.y+z; };
foo.call({x: 25, y: 6}, 11); ➟ 42
foo.apply({x: 25, y: 6}, [11]); ➟ 42
Array.prototype.push.call({length: 6}, 'a');
➟ { length: 7, 6: 'a' }
Slide 20
Slide 20 text
Any function may be called
with particular this state
var foo = function(z) { return this.x+this.y+z; };
foo.call({x: 25, y: 6}, 11); ➟ 42
foo.apply({x: 25, y: 6}, [11]); ➟ 42
Array.prototype.push.call({length: 6}, 'a');
➟ { length: 7, 6: 'a' }
Slide 21
Slide 21 text
And even lambda does!
(function(z) {
return this.x+this.y+z;
}).call({x: 25, y: 6}, 11);
➟ 42
Slide 22
Slide 22 text
This means that value
of this always depends
on the place where
you do a call
Slide 23
Slide 23 text
New scope level is
created only for
functions, there is no
block-scoping
So there is no inner-blocks for if-s and for-s and all that stuff.
Slide 24
Slide 24 text
Common pitfall
for (var i = 0; i < 42; i++) {
other_func(..., function() {
console.log(i);
});
});
because of its lambda nature, inner function may be called in
any time after the fact the loop was performed — it may never
be called at all or may be called several times, but it's only
other_func knows when
since your i variable is just a pointer to a value, independently of the
time when lambda was called, it is already a 42
Slide 25
Slide 25 text
Common pitfall
for (var i = 0; i < 42; i++) {
other_func(..., (function(actual_i) {
return function() {
console.log(actual_i);
});
})(i));
});
Now you create a wrapping lambda that is
called immediately and saves the actual value of
i to some another var, say actual_i
solution
Slide 26
Slide 26 text
Now, to the
interesting part
Slide 27
Slide 27 text
Deferred functions
Slide 28
Slide 28 text
Required to achieve
'foofoobarxbee'
parse(
twice(str('foo')),
str('bar'),
any_char(),
str('bee')
);
Slide 29
Slide 29 text
Required to achieve
pipe(
process('foo.sh'),
process('bar.sh'),
stream_to('file.text')
);
(synchronous, one-by-one, for now,
but an asynchronous version to come
later in the very same presentation)
Slide 30
Slide 30 text
A way
function twice(f) {
var chunk = f();
return (search(str, pos, chunk) &&
search(str,
pos+chunk.length, chunk);
}
twice = def(twice);
Required to achieve
queue(load_file)(
['file1', 'file2', 'file3']
);
(this one looks asynchronous and
it is factually able to be asynchronous,
every call is such, and they are performed
in the given strict order)
Slide 44
Slide 44 text
A way
function load_file(name, next) {
setTimeout(function() {
....
next(/* file */);
}, 1000);
}
Slide 45
Slide 45 text
A tool
function queue(f) {
return function(values) {
function __next() {
if (!values.length) return;
f(values.shift(), __next);
}
__next();
}
}
(we omit error handling to give you
clear view towards the process, but you
may easily get on_error or on_complete
among with f and pass them together with __next)
Slide 46
Slide 46 text
What happens?
Slide 47
Slide 47 text
An example
http://codepen.io/shamansir/pen/AaHqy
Slide 48
Slide 48 text
Composed functions
Slide 49
Slide 49 text
Required to achieve
compose(open_file,
read_file,
show_file,
close_file)('test.file');
(this one gives a next-calls-combined callback
to every function, so each of them
decides by itself if call it after synchronous
or asynchronous process)
Slide 50
Slide 50 text
Required to achieve
compose(open_file,
read_file,
show_file,
close_file)('test.file');
(also it passes the every previous result
to the next function and that's why it's so
MIGHTY)
Slide 51
Slide 51 text
A way
function open_file(name, callback) {
... // callback may be called asynchronously
}
function read_file(handle, callback) {
... // callback may be called asynchronously
}
function show_file(contents, callback) {
... // callback may be called asynchronously
}
function close_file(handle, callback) {
... // callback may be called asynchronously
}
Slide 52
Slide 52 text
A tool
function compose() {
var fs = arguments,
fl = fs.length,
fi = fl,
stack = [];
if (!fi) throw new Error('Please pass some functions');
while (fi--) {
stack[fi] = (function(f, cb) {
return function(res) { f(res, cb); }
})(fs[fi], stack[fi+1] || null);
}
return function(initial) {
stack[0](initial);
}
}
Slide 53
Slide 53 text
What happens?
Slide 54
Slide 54 text
An example
http://codepen.io/shamansir/pen/Funwt
Slide 55
Slide 55 text
For generators in JS,
(yes, the ones with yield)
see
And if you'll look in the source,
you now can make it
a few-liner too.
Lyfe.js
Slide 56
Slide 56 text
For generators in JS,
(yes, the ones with yield)
see
an article about
And if you'll look in the source,
you now can make it
a few-liner too.
Lyfe.js
Slide 57
Slide 57 text
Most of the functional
approaches are few-
liners
You probably don't need special libraries in these cases.
Slide 58
Slide 58 text
No content
Slide 59
Slide 59 text
Now when you've
mastered functions,
you may start to master
objects.
Just treat them as a states or instances and
never (please, never) give them methods if
you are willing to iterate over them in
future.
Slide 60
Slide 60 text
Object with data is a hash.
{ val1: 3, val2: '17', val3: function... }
You may iterate over it.
(and it is really easy to mix objects like this one)
Slide 61
Slide 61 text
Object, created from
some prototype is
a special instance
function A() { this.a = smth; }
A.prototype.method = function() {}
var foo = new A();
There's no meaning in iterating over it.
Slide 62
Slide 62 text
And don't forget 'bout
the ducks.
Slide 63
Slide 63 text
Fin.
All of the paintings are created by shaman.sir with the
help of iOS Paper app.