Pull to refresh

Техники сжатия кода

Reading time 5 min
Views 5.4K
Original author: Jed Schmidt
Джед Шмидт, Томас Фухс и Дастин Диаз — достаточно известные в JavaScript-коммьюнити ребята в последнее время нашли себе новую развлекуху — писать полезные штуки размером не больше одного твита, то есть 140 байт. Даже домен зарегали — 140byt.es, куда приглашаются все желающие попробовать свои силы в написании супер-компактных функций.

Естественно, в ход идут все самые изощренные способы и техники уменьшения размера исходника. У них есть вики-страничка с советами, которую я и решил перевести.

Сразу оговорюсь, что читаемость обработанного таким образом кода стремится к нулю, так что использовать эти трюки стоит только в случаях, когда размер действительно превыше всего. Например, при участии в конкурсе JS1k.

Итак.

Arguments


Используйте однобуквенные позиционные аргументы в алфавитном порядке


Поскольку аргументы функции должны быть как можно более короткими, и скорее всего будут использованы по несколько раз во время выполнения, проще рассматривать их с точки зрения позиции и именовать в алфавитном порядке, вместо того, чтобы пытаться давать им сколько-либо осмысленные имена.
function(t,d,v,i,f){...} // до
function(a,b,c,d,e){...} // после


Проверяйте наличие аргументов вместо длины


Можно использовать in для проверки наличия аргумента.
arguments.length>1||(cb=alert) // до
1 in arguments||(cb=alert)     // после


Переменные


Используйте «лишние» аргументы вместо var


Можно сэкономить несколько байт указав лишний аргумент в функции, вместо объявления переменной с помощью var:
function(a){var b=1;...} // до
function(a,b){b=1;...}   // после


Используйте переменные по несколько раз


setTimeout(function(){for(var i=10;i--;)... }, a) // до
setTimeout(function(){for(a=10;a--;)... }, a)     // после


Используйте присваивание там, где это возможно


Поскольку оператор присваивания возвращает присваиваемое значение, можно использовать присваивание и проверку одновременно:
a=this.localStorage;if(a){...} // до
if(a=this.localStorage){...}   // после


Используйте массив чтобы поменять местами переменные


Массив можно использовать как временное хранилище, чтобы не объявлять лишнюю переменную.
var a=1,b=2,c;c=a;a=b;b=c // до
var a=1,b=2;a=[b,b=a][0]  // после


Используйте приведение типов при сложении


Приведение типов в JS работает весьма странно и является одним из самых распространенных источником багов. Тем не менее, его можно использовать разными интересными способами для уменьшения размеров кода.
Наример, в реализации pubsub Джед Шмидт декрементировал переменную с отрицательным числом, а затем прибавлял ее к строке, получая что-то вида "somestring-123".
После этого в другом месте использовал .split('-') для получения исходной строки.

Циклы


Опускайте тело цикла


Зачастую можно реализовать всю логику внутри условий и сэкономить на теле цикла.
Хороший пример этого подхода можно посмотреть в функции timeAgo.

Используйте for вместо while


for и while обычно занимают одинаково количество байт, но for позволяет получить больший контроль и больше возможностей для присваивания.
while(i--){...} // до
for(;i--;){...} // после

i=10;while(i--){...} // до
for(i=10;i--;){...}  // после


Используйте быструю итерацию по «правдивым» массивам


Если у вас есть массив, все члены которого заведомо приводятся к true, можно использовать более короткую запись цикла:
for(a=[1,2,3,4,5],l=a.length,i=0;i<l;i++){b=a[i];...} // до
for(a=[1,2,3,4,5],i=0;b=a[i++];){...}                 // после


Используйте for..in с присваиванием для получения ключей объектов


a=[];for(b in window)a.push(window[b]) // до
a=[];i=0;for(a[i++]in window);         // после


Операторы


Выучите приоритет операторов


Эти знания могут помочь неплохо сэкономить на скобках.
Начать можно с изучения этой статьи на сайте Mozilla.

Используйте ~ c indexOf


hasAnF="This sentence has an f.".indexOf("f")>=0 // до
hasAnF=~"This sentence has an f.".indexOf("f")   // после


Используйте запятую для последовательного выполнения операторов вместо блока


with(document){open();write("hello");close()} // до
with(document)open(),write("hello"),close()   // после


Используйте более короткие способы записи undefined


Вместо undefined можно использовать []._ или void 0.
Есть варианты ""._, 1.._ и [][0], но они намного медленнее.

Удаляйте необязательные пробелы перед операторами


Иногда пробелы после операторов можно безболезненно удалить.
typeof [] // до
typeof[]  // после


Числа


Используйте ~~ или 0| вместо Math.floor


rand10=Math.floor(Math.random()*10) // до
rand10=0|Math.random()*10           // после


Используйте экспоненциальный формат для больших круглых чисел


million=1000000 // до
million=1e6     // после


Используйте побитовые сдвиги для больших бинарных чисел


color=0x100000 // до
color=1<<20    // после


Используйте 1/0 вместо Infinity


Это короче. Кроме того, делить на нуль всегда весело.
[Infinity,-Infinity] // до
[1/0,-1/0]           // после


Используйте «ложность» нуля


Вместо сравнивания чисел иногда короче свести значение к нулю и проверить его истинность.
a==1||console.log("not one") // до
~-a&&console.log("not one")  // после


Используйте ~ чтобы изменить любое значение на единицу


В сочетании с унарным минусом это дает возможность, например, инкрементировать любую, даже еще не определенную переменную.
// i = undefined
i=i||0;i++ // до
i=-~i      // после


Строки


Разбивайте строки с помощью нуля


Можно сэкономить два байта при разбиении строк методом split, если в качестве разделителя использовать нуль:
'alpha,bravo,charlie'.split(',') // до
'alpha0bravo0charlie'.split(0)   // после


Используйте браузерный метод link


Строки в браузерах имеют не очень известный метод link, который создает html-ссылку.
html="<a href='"+url+"'>"+text+"</a>" // до
html=text.link(url)                   // после


Используйте методы replace и exec для итерации по строкам


Эти методы позволяют передавать функцию в качестве второго аргумента. Этим можно воспользоваться для удобной итерации по строке.
Примеры использования: templates и UUID.

Используйте массивы для создания простых строк


for(a="",i=32;i--;)a+=0 // до
a=Array(33).join(0)     // после


Регулярные выражения


Используйте {n} для укорачивания рeгулярных выражений. Например /\d{3}/ вместо /\d\d\d/. И наоборот /\d\d/ вместо /\d{2}/.

Можно использовать eval вместо конструктора регулярки:
r=new RegExp("{"+p+"}","g") // до
r=eval("/{"+p+"}/g")        // после


Boolean


Используйте ! с цифрами для создания true и false.
[true,false] // до
[!0,!1]      // после


Функции


Используйте именованные функции для рекурсии вместо циклов


Зачастую это получается короче, поскольку позволяет протаскивать значения через стек, без лишних переменных.
В качестве примера функция walk.

Используйте именованные функции для хранения состояния


Если надо хранить состояние между вызовами функции, функцию можно использовать как объект и хранить данные в ее свойствах:
function(i){return function(){console.log("called "+(++i)+" times")}}(0) // до
(function a(){console.log("called "+(a.i=-~a.i)+" times")})              // после
0,function a(){console.log("called "+(a.i=-~a.i)+" times")}              // еще вариант


Опускайте скобки при вызове конструктора без аргументов


now = +new Date() // до
now = +new Date   // после


Опускайте ключевое слово new там, где это возможно


Некоторым конструкторам вовсе не обязательно ключевое слово new.
r=new Regexp(".",g) // до
r=Regexp(".",g)     // после

l=new Function("x","console.log(x)") // до
l=Function("x","console.log(x)")     // после


Оператор return


Когда надо вернуть что-то отличное от переменной, ставить пробел после return не обязательно.
return ['foo',42,'bar']; // до
return['foo',42,'bar'];  // после
return {x:42,y:417}; // до
return{x:42,y:417};  // после
return .01; // до
return.01;  // после


Пока все.

Вообще, рекомендую ознакомиться с плодами их творчества. В попытках уместить сложные вещи в 140 байт ребята иногда просто творят чудеса. Я думаю, даже опытный программист найдет для себя что-то новое и интересное в их коде.
Tags:
Hubs:
+134
Comments 121
Comments Comments 121

Articles