Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Functional JavaScript with Lo-Dash.js Frontrend Vol.5 ઘਫᠳޗ / @1000ch CyberAgent, Inc.

Slide 3

Slide 3 text

About me @1000ch WebDeveloper@CyberAgent 1೥લ·ͰProgrammer

Slide 4

Slide 4 text

Output  http://1000ch.net  @1000ch  http://github.com/1000ch  http://github.com/enja-oss

Slide 5

Slide 5 text

Agenda  Object-Oriented & Functional  Underscore.js & Lo-Dash.js  Conclusion!

Slide 6

Slide 6 text

Object-Oriented AND Functional

Slide 7

Slide 7 text

Functional ???

Slide 8

Slide 8 text

Functional Programming  ʰ਺ֶతͳؔ਺ͷධՁΛߦ͍ɺঢ়ଶ΍σʔλͷม ߋΛߦΘͳ͍ϓϩάϥϛϯάύϥμΠϜʱ via Wikipedia  ؔ਺ܕͱݴΘΕͯ΋Πϝʔδ͠ʹ͍͘…ɻ

Slide 9

Slide 9 text

ԡ͠دͤΔFunctional  Haskellͱ͔Clojureͱ͔ɻ  Twitter͸ScalaΛ࠾༻ɻ  JavaScript΋Functionalʁ

Slide 10

Slide 10 text

఩ֶతͳ࿩Λ͢Δؾ͸ ͍͟͝·ͤΜʂ FunctionalͳΞϓϩʔν΋ͯ͠ΈͯͶ͍ͬͯ͏࿩

Slide 11

Slide 11 text

Object-Oriented ???

Slide 12

Slide 12 text

Object-Oriented Programming  ʰΦϒδΣΫτಉ࢜ͷ૬ޓ࡞༻ͱͯ͠ɺγεςϜ ͷৼΔ෣͍Λଊ͑Δߟ͑ํʱ via Wikipedia  ͭ·ΓʰϓϩάϥϜͰ࣮ݱ͍ͨ͠ϞσϧΛந৅Խ ͨ͠΋ͷʱͰ͋Δɻ

Slide 13

Slide 13 text

OOPͷྫ͑͹…

Slide 14

Slide 14 text

ೣΛOOPͰදݱ͢Δ var Animal = function(word) { this.word = word; }; Animal.prototype.cry = function() { console.log(this.word); }; var Cat = function() { Animal.call(this, "Nya-"); }; Cat.prototype = Object.create(Animal.prototype); Cat.prototype.constructor = Animal; new Cat().cry(); //=>Nya-

Slide 15

Slide 15 text

jQuery΋OOP? var $headline = $(".headline"); $headline.css({ "font-size": "24px" }); var $paragraph = $("p"); $paragraph.css({ "background": "#000", "color": "#fff" }).addClass("breakAll"); var $button = $("button"); $button.on("click", function() { console.log("button is clicked!"); });

Slide 16

Slide 16 text

ΦϒδΣΫτࢦ޲ͷ໰୊఺

Slide 17

Slide 17 text

 ΦϒδΣΫτಉ࢜ͷؔ܎͕ີʹͳΓ͕ͪ  ໾ׂ͕େ͖͘ͳΓ͗ͯ͢Ϋϥε͕ෳࡶʹͳΓ͕ͪ  ܧঝ͞Ε͗ͯ͢มߋͰ͖ͳ͘ͳΓ͕ͪ OOP๊͕͕͑ͪͳ໰୊

Slide 18

Slide 18 text

“ίʔυͷ໾ׂ෼୲͕ෳࡶͰɺίʔυͷ ໾ׂ͕ີ઀ͳؔ܎Λ͍࣋ͬͯΔͱ ςετΛߦ͏͜ͱ͕೉͘͠ͳΔɻ” - @cssradar at Frontrend Vol.4 https://speakerdeck.com/studiomohawk/testable-javascript

Slide 19

Slide 19 text

ͭ·Δͱ͜Ζɺ อकੑΛҡ࣋͠ʹ͍͘ɻ

Slide 20

Slide 20 text

jQueryͷอक͠Ζͬͯ ݴΘΕͯ΋ɺͰ͖·ͤΜɻ

Slide 21

Slide 21 text

FunctionalͳΞϓϩʔν͕ ղܾͯ͘͠ΕΔʂ ʢ͔΋͠Εͳ͍ʂʣ

Slide 22

Slide 22 text

Funtional Function  Ҿ਺͕ಉ͡Ͱ͋Ε͹ग़ྗ΋ಉ͡Ͱ͋Δ  Ռͨ͢໾ׂ͕؆ܿͰ෼ׂ͞Ε͍ͯΔ͜ͱ

Slide 23

Slide 23 text

Funtional Function  Ҿ਺͕ಉ͡Ͱ͋Ε͹ग़ྗ΋ಉ͡Ͱ͋Δ  Ռͨ͢໾ׂ͕؆ܿͰ෼ׂ͞Ε͍ͯΔ͜ͱ

Slide 24

Slide 24 text

This is bad... var sortedString = function(array) { array.sort(); return array.join(); }; var array1 = [1, 6, 8, 4, 9, 0, 3, 5, 2, 7]; console.log(sortedString(array1)); //=>0,1,2,3,4,5,6,7,8,9 console.log(array1); //=>[0,1,2,3,4,5,6,7,8,9] //Ҿ਺͕มߋ͞Εͯ͠·͍ͬͯΔ…ɻ

Slide 25

Slide 25 text

This is better !!! var sortedString = function(array) { var buffer = array.slice(); buffer.sort(); return buffer.join(); }; var array1 = [1, 6, 8, 4, 9, 0, 3, 5, 2, 7]; console.log(sortedString(array1)); //=>0,1,2,3,4,5,6,7,8,9 console.log(array1); //=>[1,6,8,4,9,0,3,5,2,7] //OK!

Slide 26

Slide 26 text

Funtional Function  Ҿ਺͕ಉ͡Ͱ͋Ε͹ग़ྗ΋ಉ͡Ͱ͋Δ  Ռͨ͢໾ׂ͕؆ܿͰ෼ׂ͞Ε͍ͯΔ͜ͱ

Slide 27

Slide 27 text

This is bad... var setElement = function() { $(".hoge").addClass("decorationClass").animate({...}); }; var initMainPage = function() { window.scrollTo(1, 0); setElement(); }; window.onload = function() { initMainPage(); };

Slide 28

Slide 28 text

This is better !!! var setElement = function(element) { $(element).addClass("decorationClass").animate({...}); }; var hideAddressBar = function() { window.scrollTo(1, 0); }; window.onload = function() { hideAddressBar(); setElement(document.getElementsByClassName(".hoge")); };

Slide 29

Slide 29 text

FunctionalͳΞϓϩʔνΛ ࢼͯ͠ΈΔɻ

Slide 30

Slide 30 text

jQueryͬΆ͍αϯϓϧ࣮૷ var $ = function(selector) { return { list: document.querySelectorAll(selector), each: function(callback) { for(var i = 0, l = this.list.length;i < l;i++) { callback(this.list[i]); } return this; }, addClass: function(className) { return this.each(function(element) { element.classList.add(className); }); } }; };

Slide 31

Slide 31 text

࢖͍ํΠϝʔδ //$ίϯετϥΫλʹCSSηϨΫλΛ౉͠ɺཁૉʹΫϥεΛ௥Ճɻ $(".parentClass .childClass").addClass("hoge");

Slide 32

Slide 32 text

͜ͷ࣮૷ͷ໰୊఺  each()΋addClass()΋ίϯετϥΫλͷ querySelectorAllʹґଘ͍ͯ͠Δɻ  ࠶ར༻ग़དྷͳ͍ɻ  ΫϥεΛ֦ு͢Δͨͼʹςετͷݟ௚͠ɻ

Slide 33

Slide 33 text

Functionalʹॻ͖௚͢ var _ = {}; _.qsa = function(selector) { return document.querySelectorAll(selector); }; _.each = function(targetObject, callback) { for(var i = 0, len = targetObject.length;i < len;i++) { callback(targetObject[i]); } }; _.addClass = function(targetElementList, className) { _.each(targetElementList, function(element) { element.classList.add(className); }); };

Slide 34

Slide 34 text

࢖͍ํΠϝʔδ //CSSηϨΫλΛ౉͠ɺཁૉΛબ୒͢Δɻ var elementList = _.qsa(".parentClass .childClass"); //औಘͨ͠ཁૉʹΫϥεΛ௥Ճ͢Δɻ _.addClass(elementList, "hoge");

Slide 35

Slide 35 text

ղܾ͞Εͨ఺  _.qsa()΋ɺ_.addClass()΋ޓ͍ʹґଘ͍ͯ͠ͳ͍ ͷͰɺ࠶ར༻Ͱ͖Δɻ  ςετέʔεͷݟ௚͕͠ൃੜ͠ʹ͍͘ɻ

Slide 36

Slide 36 text

FunctionalͳΞϓϩʔν͕ ΋ͨΒ͢ϝϦοτ

Slide 37

Slide 37 text

Simplicity ϝιουؒͷґଘੑ͕ૄʹͳΔ͜ͱͰɺ ίʔυ͕γϯϓϧʹͳΔɻ

Slide 38

Slide 38 text

Testablity ؔ਺ͷ໾ׂ͕؆ܿʹͳΔ͜ͱͰɺ ςετ͕ॻ͖΍͘͢ͳΔɻ

Slide 39

Slide 39 text

Maintainablity SimplicityͱTestablityʹΑͬͯɺ อकੑͷ޲্͕ظ଴Ͱ͖Δɻ

Slide 40

Slide 40 text

Underscore.js AND Lo-Dash.js

Slide 41

Slide 41 text

FunctionalͳΞϓϩʔνͷ ϝϦοτ͸Θ͔ͬͨʂ

Slide 42

Slide 42 text

ϢʔςΟϦςΟΛͭͬͨ͘Γ อक͢Δίετ͕…ɻ

Slide 43

Slide 43 text

༏लͳϥΠϒϥϦ͕͋Γ· ͢ɻ࢖͍·͠ΐ͏ɻ ʢ※΋ͪΖΜࣗ࡞Ͱ΋OKͰ͢ʣ

Slide 44

Slide 44 text

http://lodash.com/

Slide 45

Slide 45 text

Lo-Dash.js  Underscore.jsͱAPIͷޓ׵ੑͷ͋ΔϥΠϒϥϦ  each()΍!rst()ͳͲɺศརͳϢʔςΟϦςΟΛඋ ͍͑ͯΔ

Slide 46

Slide 46 text

͋Εʁ ͡Ό͋Underscore.js͸ʁ

Slide 47

Slide 47 text

http://underscorejs.org/

Slide 48

Slide 48 text

Underscore.jsͰ΋OK  Lo-Dash.jsΑΓϑΝΠϧαΠζ͕ܰྔ  ίʔυ͕ͱͯ΋៉ྷͳͷͰίʔυϦʔσΟϯάʹ ޲͍ͯΔ

Slide 49

Slide 49 text

ͳͥ Lo-Dash.jsΛબͿͷ͔ʁ

Slide 50

Slide 50 text

- John-David Dalton at StackOver"ow “better overall performance and optimizations for large arrays/object iteration, and more !exibility with custom builds and template pre- compilation utilities.” http://stackover"ow.com/questions/13789618/di#erences-between- lodash-and-underscore

Slide 51

Slide 51 text

ʰେ͖ͳ഑ྻ΍ΦϒδΣΫτͷྻڍʹ࠷దԽ͞Ε͓ͯ ΓɺશମతʹύϑΥʔϚϯε͕վળ͞Ε͍ͯΔɻ· ͨɺΧελϜϏϧυ΍ςϯϓϨʔτͷϓϦίϯύΠϧ ͳͲɺΑΓॊೈͳ࡞Γʹͳ͍ͬͯΔɻʱ

Slide 52

Slide 52 text

 ࣮ߦύϑΥʔϚϯε͕ྑ͍  ໰୊͕৭ʑղܾ͞Ε͍ͯ·͢  ΧελϜϏϧυͰ͖·͢  Underscore.jsʹޓ׵ੑ͋Γ·͢

Slide 53

Slide 53 text

Performance of Lo-Dash.js

Slide 54

Slide 54 text

Compare Performance(1) Underscore#forEach Native#forEach Lo-Dash#forEach with bind Lo-Dash#forEach Native#for 0 1250000 2500000 3750000 5000000

Slide 55

Slide 55 text

͏ʔΜɺ΍ͬͺΓ forจ͕1൪ߴ଎…ɻ

Slide 56

Slide 56 text

ͦΕͰ΋Lo-Dash.jsΛ ࢖͏Ձ஋͕͋Δɻ

Slide 57

Slide 57 text

_.each() via Underscore.js

Slide 58

Slide 58 text

_.each = _.forEach = function(obj, iterator, context) { if (obj == null) return; if (nativeForEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context); } else if (obj.length === +obj.length) { for (var i = 0, l = obj.length; i < l; i++) { if (iterator.call(context, obj[i], i, obj) === breaker) return; } } else { for (var key in obj) { if (_.has(obj, key)) { if (iterator.call(context, obj[key], key, obj) === breaker) return; } } } };

Slide 59

Slide 59 text

_.each = _.forEach = function(obj, iterator, context) { if (obj == null) return; if (nativeForEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context); } else if (obj.length === +obj.length) { for (var i = 0, l = obj.length; i < l; i++) { if (iterator.call(context, obj[i], i, obj) === breaker) return; } } else { for (var key in obj) { if (_.has(obj, key)) { if (iterator.call(context, obj[key], key, obj) === breaker) return; } } } };

Slide 60

Slide 60 text

_.each = _.forEach = function(obj, iterator, context) { if (obj == null) return; if (nativeForEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context); } else if (obj.length === +obj.length) { for (var i = 0, l = obj.length; i < l; i++) { if (iterator.call(context, obj[i], i, obj) === breaker) return; } } else { for (var key in obj) { if (_.has(obj, key)) { if (iterator.call(context, obj[key], key, obj) === breaker) return; } } } }; ωΠςΟϒͷforEach͕࢖͑Δ ৔߹͸ͦΕΛ࣮ߦ͍ͯ͠Δ

Slide 61

Slide 61 text

_.each() via Lo-Dash.js

Slide 62

Slide 62 text

function forEach(collection, callback, thisArg) { var index = -1, length = collection ? collection.length : 0; callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg); if (typeof length == 'number') { while (++index < length) { if (callback(collection[index], index, collection) === false) { break; } } } else { forOwn(collection, callback); } return collection; }

Slide 63

Slide 63 text

function forEach(collection, callback, thisArg) { var index = -1, length = collection ? collection.length : 0; callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg); if (typeof length == 'number') { while (++index < length) { if (callback(collection[index], index, collection) === false) { break; } } } else { forOwn(collection, callback); } return collection; }

Slide 64

Slide 64 text

function forEach(collection, callback, thisArg) { var index = -1, length = collection ? collection.length : 0; callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg); if (typeof length == 'number') { while (++index < length) { if (callback(collection[index], index, collection) === false) { break; } } } else { forOwn(collection, callback); } return collection; } جຊతʹwhileจΛ࢖͍ͬͯΔ

Slide 65

Slide 65 text

Compare Performance(2) Underscore#forEach Array Underscore#forEach Object Lo-Dash#forEach Object Lo-Dash#forEach Array 0 750000 1500000 2250000 3000000

Slide 66

Slide 66 text

Compare Performance(2) Underscore#forEach Array Underscore#forEach Object Lo-Dash#forEach Object Lo-Dash#forEach Array 0 750000 1500000 2250000 3000000 forจͱArray.forEachͷ ͕ࠩग़ͯΔ

Slide 67

Slide 67 text

Compare Performance(2) Underscore#forEach Array Underscore#forEach Object Lo-Dash#forEach Object Lo-Dash#forEach Array 0 750000 1500000 2250000 3000000 whileจͳͷͰ΄ͱΜͲ ͕ࠩग़͍ͯͳ͍

Slide 68

Slide 68 text

ΧελϜϏϧυͱ Underscore.jsޓ׵

Slide 69

Slide 69 text

Modern build Legacy build Mobile build Strict build Underscore build Backbone build Ϟμϯϒϥ΢β޲͚ͷϏϧυɻ ϨΨγʔϒϥ΢βରԠ͕ͳ͞Ε͍ͯΔɻ ؔ਺ͷίϯύΠϧ͕͞Ε͍ͯͳ͍ ಡΈऔΓઐ༻ϓϩύςΟΛ্ॻ͖͠Α͏ ͱͨ͠ͱ͖ʹΤϥʔΛ౤͛Δɻ Underscore.jsʹAPIΛ߹Θͤͯ͋Δɻ Backbone.jsʹඞཁͳAPIͷΈඋ͑Δɻ

Slide 70

Slide 70 text

Modern build Legacy build Mobile build Strict build Underscore build Backbone build Ϟμϯϒϥ΢β޲͚ͷϏϧυɻ ϨΨγʔϒϥ΢βରԠ͕ͳ͞Ε͍ͯΔɻ ؔ਺ͷίϯύΠϧ͕͞Ε͍ͯͳ͍ ಡΈऔΓઐ༻ϓϩύςΟΛ্ॻ͖͠Α͏ ͱͨ͠ͱ͖ʹΤϥʔΛ౤͛Δɻ Underscore.jsʹAPIΛ߹Θͤͯ͋Δɻ Backbone.jsʹඞཁͳAPIͷΈඋ͑Δɻ

Slide 71

Slide 71 text

Compare File Size lodash.min.js lodash.underscore.min.js underscore.min.js 0 7500 15000 22500 30000 compressed gzipped

Slide 72

Slide 72 text

Compare File Size lodash.min.js lodash.underscore.min.js underscore.min.js 0 7500 15000 22500 30000 compressed gzipped gzip͢Ε͹͞΄ͲมΘΒͳ͍ʂ ʢ7,701bytesʣ

Slide 73

Slide 73 text

৭ʑߟྀ͢Δͱݱ࣌఺Ͱ͸ Lo-Dash.js͕ྑͦ͞͏…ɻ

Slide 74

Slide 74 text

͔͠͠Underscore.jsͷ ඒ͍࣮͠૷͸ ඇৗʹࢀߟʹͳΔɻ

Slide 75

Slide 75 text

_.pluck() via Underscore.js

Slide 76

Slide 76 text

var stooges = [ {name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60} ]; _.pluck(stooges, 'name'); //=> ["moe", "larry", "curly"]

Slide 77

Slide 77 text

_.pluck = function(obj, key) { return _.map(obj, function(value){ return value[key]; }); };

Slide 78

Slide 78 text

…ඒ͍͠ɻ

Slide 79

Slide 79 text

_.compose = function(/*, funs */) { var functions = arguments; return function() { var args = arguments; for (var i = functions.length - 1; i >= 0; i--) { args = [functions[i].apply(this, args)]; } return args[0]; }; };

Slide 80

Slide 80 text

var plusFive = function(num) { return num + 5; }; var multiplyThree = function(num) { return num * 3; }; var plus5_multiply3 = _.compose(multiplyThree, plusFive); plus5_multiply3(4); //=>27

Slide 81

Slide 81 text

ΑΓFunctionalʹॻͨ͘Ίʹ ϓϥάΠϯ͕͋Γ·͢ɻ

Slide 82

Slide 82 text

https://github.com/documentcloud/underscore-contrib

Slide 83

Slide 83 text

_.pipeline = function(/*, funs */){ var functions = arguments; return function(seed) { return _.reduce(functions, function(l, r) { return r(l); }, seed); }; };

Slide 84

Slide 84 text

var plusFive = function(num) { return num + 5; }; var multiplyThree = function(num) { return num * 3; }; var multiply3_plus5 = _.pipeline(multiplyThree, plusFive); multiply3_plus5(4); //=>17

Slide 85

Slide 85 text

http://dtao.github.io/lazy.js/

Slide 86

Slide 86 text

function square(x) { return x * x; } function inc(x) { return x + 1; } function isEven(x) { return x % 2 === 0; } var result = _.chain(array) .map(square).map(inc) .filter(isEven).take(5).value(); var result = Lazy(array) .map(square).map(inc) .filter(isEven).take(5);

Slide 87

Slide 87 text

http://functionaljs.org/

Slide 88

Slide 88 text

http://moutjs.com/

Slide 89

Slide 89 text

ͲΕ΋DOMΛૢ࡞͢Δ࣮૷͸ ؚΜͰ͍ͳ͍ɻ ※͋͘·ͰɺJavaScriptͷUtilityͰ͋ΔͨΊɻ

Slide 90

Slide 90 text

DOMૢ࡞ͷAPIΛ ఏڙ͢Δ֦ுΛ࡞ͬͯΈͨɻ ※ࢀߟఔ౓ʹͲ͏ͧɻ

Slide 91

Slide 91 text

https://github.com/1000ch/_.domextend

Slide 92

Slide 92 text

ಛ௃  ཁૉબ୒API  ΠϕϯτͷόΠϯυAPI  CSSΫϥεͷ෇͚֎͠API  ͍ܰ(mini!edͰ3KB͘Β͍)

Slide 93

Slide 93 text

Conclusion !

Slide 94

Slide 94 text

OBJECT-ORIENTED TO FUNCTIONAL

Slide 95

Slide 95 text

OBJECT-ORIENTED TO FUNCTIONAL

Slide 96

Slide 96 text

OBJECT-ORIENTED WITH FUNCTIONAL

Slide 97

Slide 97 text

෺ࣄͷந৅Խ͸ΦϒδΣΫτ ࢦ޲Ͱ͔͠Ͱ͖ͳ͍ɻ

Slide 98

Slide 98 text

USE LO-DASH.jS WATCH UNDERSCORE.JS

Slide 99

Slide 99 text

Underscore.jsͱ͔MOUT͋ͨ Γ͕៉ྷͳͷͰࢀߟʹʂ

Slide 100

Slide 100 text

Thank you ! by @1000ch

Slide 101

Slide 101 text

http://www."ickr.com/photos/vicpowles/7229138156/ http://www."ickr.com/photos/49875617@N06/8770578796/ http://www."ickr.com/photos/vicpowles/7229138156/ http://www."ickr.com/photos/scalamax/8764370935/ http://www."ickr.com/photos/jody_art/8758073909/ http://www."ickr.com/photos/liza-photography/6272074016/ http://www."ickr.com/photos/51710089@N08/8758089618/ Photo Credits

Slide 102

Slide 102 text

http://fontawesome.io/ http://font.ubuntu.com/ https://github.com/adobe/Source-Code-Pro http://www.fontsquirrel.com/fonts/bebas-neue Font Credits