Добрый день!
Не знаю, будет ли кому интересно, но соорудил сегодня такое чудо: DeepClone, упихивающийся в 140 байт.
Если кто-то такое уже делал и постил, ткните, пожалуйста, носом. Я в формате твитов нашёл только неглубокие копирования. Ну и не исключаю, что какой-нибудь применённый хак находится в списке запрещённыхпрепаратов приёмов, а за его использование полагаются страшные кары :)
Из недостатков — всё то же, что и у клонирования с помощью функции extend из jQuery: не ест стандартные объекты типов Boolean, String, Date, игнорирует prototype и constructor и зависает на кольцах.
Достоинство одно и, по-большей части, чисто эстетическое — размер.
Тестировал в Firefox, Chromium, Opera, IE8 и в умолчальном андроидном браузере.
Под катом — код и небольшой рассказ о том, как это работает.
Для начала, читабельная версия (назвается dup потому, что иначе в 140 байт не сжимается):
Что здесь происходит:
Если объект — простой (строка, число, boolean), просто возвращаем его, дальше проверяем, что объект — не null (typeof(null) тоже == «object»). Теперь создаём результат (массив или объект) и пробегаем по свойствам, рекурсивно их клонируя.
В общем, всё просто. Теперь почти 300 байт надо ужать в два раза.
Вспоминаем некоторые вещи, которые нам помогут:
— typeof — это оператор, и ему скобки не нужны;
— у ?: приоритет самый низкий, так что скобки слева опять-таки можно опустить;
— null && {} — это null, а obj && {} — это obj;
— for(var i in null) проходит без ошибки, не делая ни одной итерации;
— параметры функции — тоже переменные, а вот передавать их все совершенно не обязательно. Это поможет нам сэкономить 4 байта на слове var с пробелом.
Исходя из этого, получаем:
Ну, или в одну строку (139 букв):
Если же увеличить допустимый размер до 150-и символов, то можно добавить ещё и обработку ссылок на самих себя (не полное разруливание колец, конечно, но хоть что-то):
Или:
Демка: pastehtml.com/view/buikhdvfe.html (чтобы посмотреть без обёртки от pastehtml, замените в ссылке слово «view» на «raw»)
UPD:
Благодаря TheShock функция ещё чуток похудела!
Его варианты:
Также поступило дополнительное предложение от mark_ablov как ещё один байт сэкономить, упразднив if:
UPD 2:
И окончательное развитие идеи — снова от TheShock:
Ровно 140 байт чистого win'а, и работающего под IE8, и с минимальной проверкой колец!
Ура, товарищи!
Gist: gist.github.com/2369704
Обновлённая демка: pastehtml.com/view/buiv8lzka.html
UPD 3,4: ultimate weapon
Для реального использования сделал ещё одну версию, не влезающую (мягко говоря) в твит, зато работающую с датами и объектными обёртками, а также полностью разруливающую любые циклы и внутренние ссылки. Однострочный вариант занимает 328 байт.
А ещё я понял, что я — чудак редкостный, ибо совсем забыл про проблемы с многофреймовостью и instanceof. Что ж, в боевой версии и это тоже теперь решено.
Gist здесь: gist.github.com/0d3e6ce689e76105f3ef
Демка тут: pastehtml.com/view/bumpwvs4q.html
Не знаю, будет ли кому интересно, но соорудил сегодня такое чудо: DeepClone, упихивающийся в 140 байт.
Если кто-то такое уже делал и постил, ткните, пожалуйста, носом. Я в формате твитов нашёл только неглубокие копирования. Ну и не исключаю, что какой-нибудь применённый хак находится в списке запрещённых
Из недостатков — всё то же, что и у клонирования с помощью функции extend из jQuery: не ест стандартные объекты типов Boolean, String, Date, игнорирует prototype и constructor и зависает на кольцах.
Достоинство одно и, по-большей части, чисто эстетическое — размер.
Тестировал в Firefox, Chromium, Opera, IE8 и в умолчальном андроидном браузере.
Под катом — код и небольшой рассказ о том, как это работает.
Для начала, читабельная версия (назвается dup потому, что иначе в 140 байт не сжимается):
function dup(o) { // "string", number, boolean if(typeof(o) != "object") { return o; } // null if(!o) { return o; // null } var r = (o instanceof Array) ? [] : {}; for(var i in o) { if(o.hasOwnProperty(i)) { r[i] = dup(o[i]); } } return r; }
Что здесь происходит:
Если объект — простой (строка, число, boolean), просто возвращаем его, дальше проверяем, что объект — не null (typeof(null) тоже == «object»). Теперь создаём результат (массив или объект) и пробегаем по свойствам, рекурсивно их клонируя.
В общем, всё просто. Теперь почти 300 байт надо ужать в два раза.
Вспоминаем некоторые вещи, которые нам помогут:
— typeof — это оператор, и ему скобки не нужны;
— у ?: приоритет самый низкий, так что скобки слева опять-таки можно опустить;
— null && {} — это null, а obj && {} — это obj;
— for(var i in null) проходит без ошибки, не делая ни одной итерации;
— параметры функции — тоже переменные, а вот передавать их все совершенно не обязательно. Это поможет нам сэкономить 4 байта на слове var с пробелом.
Исходя из этого, получаем:
function dup(o,i,r) { if(typeof o != "object") return o; r = o instanceof Array ? [] : o&&{}; for(i in o) if(o.hasOwnProperty(i)) r[i] = dup(o[i]); return r }
Ну, или в одну строку (139 букв):
function dup(o,i,r){if(typeof o!="object")return o;r=o instanceof Array?[]:o&&{};for(i in o)if(o.hasOwnProperty(i))r[i]=dup(o[i]);return r}
Если же увеличить допустимый размер до 150-и символов, то можно добавить ещё и обработку ссылок на самих себя (не полное разруливание колец, конечно, но хоть что-то):
r[i] = (o[i] === o) ? r : dup(o[i]);
Или:
function dup(o,i,r){if(typeof o!="object")return o;r=o instanceof Array?[]:o&&{};for(i in o)if(o.hasOwnProperty(i))r[i]=o[i]===o?r:dup(o[i]);return r}
Демка: pastehtml.com/view/buikhdvfe.html (чтобы посмотреть без обёртки от pastehtml, замените в ссылке слово «view» на «raw»)
UPD:
Благодаря TheShock функция ещё чуток похудела!
Его варианты:
function dup(o,i,r) { r=o; if(r && typeof o == "object") { r = o instanceof Array ? [] : {}; for(i in o) if(o.hasOwnProperty(i)) r[i] = dup(o[i]); } return r } // 135 function dup(o,i,r){r=o;if(r&&typeof o=="object"){r=o instanceof Array?[]:{};for(i in o)if(o.hasOwnProperty(i))r[i]=dup(o[i])}return r} // отказ от ie8, 133 символа: function dup(o,i,r){r=o;if(r&&typeof o=="object"){r=Array.isArray(o)?[]:{};for(i in o)if(o.hasOwnProperty(i))r[i]=dup(o[i])}return r}
Также поступило дополнительное предложение от mark_ablov как ещё один байт сэкономить, упразднив if:
o.hasOwnProperty(i)?r[i]=dup(o[i]):1
UPD 2:
И окончательное развитие идеи — снова от TheShock:
function c(o,i,r){if(o&&typeof o=="object"){r=o instanceof Array?[]:{};for(i in o)o.hasOwnProperty(i)?r[i]=o[i]===o?r:c(o[i]):0}return r||o}
Ровно 140 байт чистого win'а, и работающего под IE8, и с минимальной проверкой колец!
Ура, товарищи!
Gist: gist.github.com/2369704
Обновлённая демка: pastehtml.com/view/buiv8lzka.html
UPD 3,4: ultimate weapon
Для реального использования сделал ещё одну версию, не влезающую (мягко говоря) в твит, зато работающую с датами и объектными обёртками, а также полностью разруливающую любые циклы и внутренние ссылки. Однострочный вариант занимает 328 байт.
А ещё я понял, что я — чудак редкостный, ибо совсем забыл про проблемы с многофреймовостью и instanceof. Что ж, в боевой версии и это тоже теперь решено.
Gist здесь: gist.github.com/0d3e6ce689e76105f3ef
Демка тут: pastehtml.com/view/bumpwvs4q.html
