Добрый день!
Не знаю, будет ли кому интересно, но соорудил сегодня такое чудо: 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