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 full-size slide

  2. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  5. 1 Function => Function

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  9. 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 full-size slide

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

    View full-size slide

  11. (function, function) => function

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  16. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  19. 2 Meta-programming

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  22. var names = argNames(fullName);
    // [’firstName’, ’lastName']

    View full-size slide

  23. 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 full-size slide

  24. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  27. Don’t try this at 127.0.0.1

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  31. 3 There is no class

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  34. Everyone forgot
    Object.create

    View full-size slide

  35. 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 full-size slide

  36. But overloading?!

    View full-size slide

  37. 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 full-size slide

  38. 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 full-size slide

  39. So what is
    Object.create really?

    View full-size slide

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

    View full-size slide

  41. "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 full-size slide

  42. 3 There is no class
    Object.create

    View full-size slide

  43. Forgotten
    funky functions
    @jakobmattsson

    View full-size slide