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

  2. Startup
    hedge fund?

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

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

    View full-size slide

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

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

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

    View full-size slide

  18. 2 Meta-programming

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

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

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  29. 3 There is no class

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  32. Everyone forgot
    Object.create

    View full-size slide

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

  34. But overloading?!

    View full-size slide

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

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

  37. So what is
    Object.create really?

    View full-size slide

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

    View full-size slide

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

  40. 3 There is no class
    Object.create

    View full-size slide

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

    View full-size slide