Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Forgotten Funky Functions

Forgotten Funky Functions

Presented at Nordic.js 2015 in Stockholm

Jakob Mattsson

September 10, 2015
Tweet

More Decks by Jakob Mattsson

Other Decks in Programming

Transcript

  1. Forgotten
    funky functions
    http://jakobm.com
    @jakobmattsson

    View Slide

  2. View Slide

  3. Startup
    hedge fund?

    View Slide

  4. View Slide

  5. View Slide

  6. Far from perfect
    and not for everything*
    or everyone
    * no, really

    View Slide

  7. View Slide

  8. Smorgasbord

    View Slide

  9. 1 Function => Function
    2 Meta-programming
    3 There is no class

    View Slide

  10. 1 Function => Function

    View Slide

  11. Error handling
    You just divided by zero, didn’t you?

    View Slide

  12. get('/users/123', function(err, response) {
    if (err) {
    cb(err);
    return;
    }
    cb(null, response.firstName);
    });

    View Slide

  13. get('/users/123', p(cb, function(response) {
    cb(null, response.firstName);
    }));

    View Slide

  14. var propagate = function(onErr, onSuccess) {
    return function(err) {
    if (err) {
    return onErr(err);
    } else {
    var slice = Array.prototype.slice;
    var rest = slice.call(arguments, 1);
    return onSuccess.apply(this, rest);
    }
    };
    };

    View Slide

  15. propagate = (onErr, onSucc) ->
    (err, rest...) ->
    if err then onErr(err) else onSucc(rest...)
    CoffeeScript
    ConferenceScript

    View Slide

  16. (function, function) => function

    View Slide

  17. (function, function) => function
    Need to solve a
    JavaScript problem?
    Add on one more function!

    View Slide

  18. var once = function(f) {
    var called = false;
    var result = null;
    return function() {
    if (!called) {
    result = f.apply(this, arguments);
    called = true;
    }
    return result;
    };
    };

    View Slide

  19. var initOnce = once(init);
    initOnce();
    initOnce();
    initOnce();
    // only called once...

    View Slide

  20. var stateful = function(f) {
    var state = {};
    return function() {
    var slice = Array.prototype.slice;
    var args = slice.call(arguments, 0);
    return f.apply(this, [state].concat(args));
    };
    };

    View Slide

  21. var once = stateful(function(state, f) {
    return function() {
    if (!state.called) {
    state.result = f.apply(this, arguments);
    state.called = true;
    }
    return state.result;
    };
    });

    View Slide

  22. 1 Function => Function
    call
    apply
    arguments
    slice
    bind
    …and closures!

    View Slide

  23. 2 Meta-programming

    View Slide

  24. View Slide

  25. var fullName = function(firstName, lastName) {
    return firstName + " " + lastName;
    };
    fullName('Jakob', ’Mattsson’);
    // ”Jakob Mattsson”

    View Slide

  26. var fullName = function(firstName, lastName) {
    return firstName + " " + lastName;
    };
    fullName('Jakob', ’Mattsson’);
    var fullName2 = argsAsObject(fullName);
    fullName2({
    firstName: ’Jakob',
    lastName: ’Mattsson'
    });

    View Slide

  27. // foo.com/fullName2?firstName=J&lastName=M
    funcs[req.path](req.query);

    View Slide

  28. var argNames = function(f) {
    var reg = /\(([\s\S]*?)\)/;
    var head = reg.exec(f)[1];
    var argCands = head.split(/[ ,\n\r\t]+/);
    var names = argCands.filter(function(x) {
    return x;
    };
    return names;
    };

    View Slide

  29. var argsAsObject = function(f) {
    var names = argNames(f);
    return function(args) {
    var argValues = names.map(function(name) {
    return args[name];
    });
    return f.apply(this, argValues);
    };
    };

    View Slide

  30. var fullName2 = argsAsObject(fullName);
    fullName2({
    firstName: ’Jakob',
    lastName: ’Mattsson'
    });

    View Slide

  31. View Slide

  32. fullName = renameArgs(fullName, [
    ’first_name’,
    ’last_name’
    ]);
    var fullName2 = argsAsObject(fullName);
    fullName2({
    first_name: ’Jakob',
    last_name: ’Mattsson'
    });

    View Slide

  33. var renameArgs = function(__uniq, argNames) {
    var parts = [
    "(function(",
    argNames.join(', ')
    ") { "
    "return __uniq.apply(this, arguments);"
    "});"
    ];
    return eval(parts.join(''));
    };

    View Slide

  34. View Slide

  35. fullName2({
    firstName: 'Jakob',
    lastName: 'Mattsson'
    });
    var fullName = spreadArguments(fullName2, [
    'firstName',
    'lastName'
    ]);
    fullName('Jakob', 'Mattsson');
    // => 'Jakob Mattsson'
    Challenge!

    View Slide

  36. 2 Meta-programming
    eval
    Function.toString()

    View Slide

  37. 3 There is no class

    View Slide

  38. new
    MyConstructor
    MyConstructor.prototype
    … and what about types??
    Original JavaScript

    View Slide

  39. class
    constructor
    extend(s)
    super
    CoffeeScript and
    ECMAScript 6

    View Slide

  40. Everyone forgot
    Object.create

    View Slide

  41. var Animal = {
    greet: function() {
    return this.speak() + ” says ” + this.name;
    }
    };
    var Dog = Object.create(Animal);
    Dog.speak = function() {
    return ”woof”;
    };
    var zelda = Object.create(Dog);
    zelda.name = ”zelda”;
    console.log(zelda.greet());

    View Slide

  42. But overloading?!

    View Slide

  43. var Animal = {
    greet: function() {
    return this.speak() + " says " + this.name;
    }
    };
    var Dog = createAndInit(Animal, {
    speak: function(superSpeak) {
    return "woof";
    },
    greet: function(superGreet) {
    return superGreet() + ", who is a dog";
    }
    });

    View Slide

  44. var createAndInit = function(source, props){
    var slice = Array.prototype.slice;
    var newObj = Object.create(source);
    Object.keys(props).forEach(function(propName){
    newObj[propName] = function(){
    var zup = source[propName];
    var boundZuper = zup ? zup(this) : null;
    var newFunc = props[propName];
    var args = slice.call(arguments, 0);
    var allArgs = [boundZuper].concat(args);
    return newFunc.apply(this, allArgs);
    };
    });
    return newObj;
    };

    View Slide

  45. So what is
    Object.create really?

    View Slide

  46. Object.create = function(x) {
    function F() {}
    F.prototype = x;
    return new F();
    };
    new
    MyConstructor
    MyConstructor.prototype

    View Slide

  47. "I have been writing JavaScript for 14 years now (...).
    The super idea is fairly important in the classical pattern,
    but it appears to be unnecessary in the prototypal and
    functional patterns.
    I now see my early attempts to support the classical
    model in JavaScript as a mistake.”
    http://www.crockford.com/javascript/inheritance.html

    View Slide

  48. 3 There is no class
    Object.create

    View Slide

  49. View Slide

  50. Forgotten
    funky functions
    http://jakobm.com
    @jakobmattsson

    View Slide