DeepClone на javascript, который можно твитнуть

в 13:03, , рубрики: clone, javascript, twitter, ненормальное программирование, метки: , ,

Добрый день!

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

Автор: lxyd

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js