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

Forgotten Funky Functions

Forgotten Funky Functions

Given at JsDay in Verona 2016-05-11

Jakob Mattsson

May 11, 2016
Tweet

More Decks by Jakob Mattsson

Other Decks in Programming

Transcript

  1. Forgotten
    funky functions
    @jakobmattsson

    View Slide

  2. View Slide

  3. View Slide

  4. ALL CHARACTERS AND
    EVENTS IN THIS SHOW--
    EVEN THOSE BASED ON REAL
    PEOPLE--ARE ENTIRELY FICTIONAL.
    ALL CELEBERTY VOICES ARE
    IMPERSONATED.....POORLY. THE
    FOLLOWING PROGRAM CONTAINS
    COARSE LANGUAGE AND DUE TO
    ITS CONTENT IT SHOULD NOT BE
    VIEWED BE ANYONE

    View Slide

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

    View Slide

  6. View Slide

  7. Smorgasbord

    View Slide

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

    View Slide

  9. 1 Function => Function

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  13. 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

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

    View Slide

  15. (function, function) => function

    View Slide

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

    View Slide

  17. var initOnce = once(init);
    initOnce();
    initOnce();
    initOnce();
    // ”init” is only called once...

    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();
    // ”init” is 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. var names = argNames(fullName);
    // [’firstName’, ’lastName']

    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. var fullNameSnake = renameArgs(fullName, [
    ’first_name’,
    ’last_name’
    ]);
    var fullName2 = argsAsObject(fullNameSnake);
    fullName2({
    first_name: ’Jakob',
    last_name: ’Mattsson'
    });

    View Slide

  33. Don’t try this at 127.0.0.1

    View Slide

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

    View Slide

  35. View Slide

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

    View Slide

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

    View Slide

  38. 3 There is no class

    View Slide

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

    View Slide

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

    View Slide

  41. Everyone forgot
    Object.create

    View Slide

  42. 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

  43. But overloading?!

    View Slide

  44. 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

  45. 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

  46. So what is
    Object.create really?

    View Slide

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

    View Slide

  48. "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

  49. 3 There is no class
    Object.create

    View Slide

  50. View Slide

  51. Forgotten
    funky functions
    @jakobmattsson

    View Slide