Как стать автором
Обновить

Комментарии 42

А o&&{} сделано для того чтобы в r null получить, если он там есть? а если нет, то будет {}.
Да, если null — будет null, который в итоге и вернётся.
Если не null — то будет пустой объект, в который дальше будут копироваться свойства исходного.
Можно добавить проверку на null, а заодно — сократить:

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
}
// 136 
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, 134 символа:
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}
Даже не 136 и 134, а 135 и 133 :)
А с отказом от IE8, заодно заменив название функции на «c», наконец-то впихиваем ровно в твит ещё и минимальную проверку на кольца:
function c(o,i,r){r=o;if(r&&typeof o=="object"){r=Array.isArray(o)?[]:{};for(i in o)if(o.hasOwnProperty(i))r[i]=o[i]===o?r:c(o[i])}return r}

Спасибо!
Можно сделать что-то типа такого и даже не отказываться от IE =)
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байтные js'ки: 140byt.es/ (в т.ч. неглубокое копирование).

Ну как, может, выложить?
Только там надо под WTFPL лицензией выкладывать.
Я не против этой лицензии.
Только проверьте последний код, а то я в нём не уверен)
Ок, приеду домой проверю :)
Демка не поломалась, так что, скорее всего, работает.
Пришла в голову безумная мысль, но я в дороге — проверить не могу. Такая конструкция имеет право на жизнь?
r = new o.constructor()
?
new o.constructor() даже работает в какой-то мере: прототип и конструктор перекидывает в клона. Правда, Date, Number, String и Boolean так и остались за бортом: естественно, создаётся новый объект.
Я только не могу понять идеологической верности/неверности данного решения: с одной стороны, часть проблем решается, с другой — ведёт себя совсем не так, как привыкли пользователи jQuery, да и другая часть проблем добавляется.
Вот и думаю теперь, что с этим делать…
Не понятно, зачем тут конструкция
o[i] === o ?
— как элемент объекта/массива может быть равен самому объекту/массиву?

Ну и для лаконичности :)
function c(o,p,y){if(o&&typeof o=="object"){p=o instanceof Array?[]:{};for(y in o)o.hasOwnProperty(y)?p[y]=c(o[!p||y]):0}return p||o}
Может быть равен, там же всё — ссылки.

Отличная идея со словом copy :)
Может быть равен
Пример? У меня не получилось такой найти, везде false.

function c(o,p,y){
	if(o&&typeof o=="object"){
		p=o instanceof Array?[]:{};
		for(y in o){
			if(o.hasOwnProperty(y)){
				if(o[y] === o){
					p[y] = p
					console.log(y + ' true')
				} else {
					p[y] = c(o[y])
					console.log(y + ' false')
				}
			}
		}
	}
	return p||o
}

c({a:1,b:2,c:{c1:1,c2:{c3:"asdasd", c4: 2*2}}}) // false
c([1,2,3,[4,5,6,[7,8,9]]]) // false
c([1,1,[1,1,[1,1]]]) // false

В такой записи, конечно! Но можно же и потом присвоить: x.field = x;
Просто я эту шткуку делал, когда мне нужно было скопировать структуру, где такие бек-референсы были. Вернее, могли быть.
Ну хорошо, может это и не частый случай :)
Хм, я на счёт бэк-референсов не подумал (никогда не юзал в таком виде). Тогда да, без этой проверки приведёт к Maximum call stack size exceeded.
Как вариант тогда:

function dup(object, copy) {
    if(typeof object == 'object') {
        copy = object instanceof Array ? [] : object && {};
        
        Object.keys(object).forEach(function(key) {
             copy[key] = dup(object[key]);
        });
    }
    
    return copy || object;
}

var object = {
    a: {
        b: {
            c: 1
        }
    }
}

dup(object);


Сжатый вариант на 9 символов короче:

function dup(o,c){if(typeof o=='object'){c=o instanceof Array?[]:o&&{};Object.keys(o).map(function(k){c[k]=dup(o[k])})}return c||o}


Ну или если забить на __proto__, то вот самый короткий вариант:
var copy = Object.create(object);


Это будет работать в браузерах, но есть ещё и IE.
Во-первых, IE8-. Во-вторых, никто не говорил о том, что запрещено использование ES5. В-третьих, тот же map не так сложно реализовать чтобы от него отказаться:

(function($) {
	'use strict';
	if(!$.map) {
		$.map = function(fn, object) {
			var i = -1, length = this.length, array = [];
			while(i++ < length) {
				if(i in this)
					array.push(fn.call(object, this[i], i, this));
			}
			return array;
		};
	}
})(Array.prototype);

Да, но в 140 байт реализованный map вместе с основной конструкцией уже не влезет :)
В IE8 map и так есть!
Если нужно еще ниже, то конечно стоит подключать реализацию.
Извиняюсь перепутал c IE9.
А можно в пост добавить?
Конечно
r=o можно в if засунуть, -2 символа.
Не выйдет: тогда надо присваивание в скобки обернуть, а это как раз те самые два символа заберёт обратно. А жаль — можно было бы вернуть поддержку IE8 за счёт этого :(
> var a = true, b = false
> if (b=a&&typeof a=="boolean") 1
> 1
> b
> true
> a
> true
Да, если
var a = true, b = null
console.log(a) // true
console.log(b) // null
if(b=a&&typeof a=="object") {} // "object" (!)
console.log(a) // true
console.log(b) // false (!)
а, да, точно.
Ну тогда можно if упразднить:
o.hasOwnProperty(i)?r[i]=dup(o[i]):1;
1 символ правда.
Array.isArray(o) есть такая штука.
Два символа даёт за счёт отказа от поддержки IE8. Так что в моём коде заменять смысла не имело, но вот в том, что из него сделал TheShock — да, смысл есть, чтобы впихнуть проверку циклов (см. комменты выше).
Можно еще использовать o.length
Ну, оно может быть и у объекта:
var дрын = {length:100,weight:50,material:"wood"}
Это да :)
Было:
o.hasOwnProperty(i)?r[i]=o[i]===o?r:c(o[i]):0

Стало:
o.hasOwnProperty(i)&&r[i]=o[i]===o?r:c(o[i])
Syntax error, однако: у присваивания приоритет меньше, чем у &&, так что слева получается неприсваиваемое.
Обновил пост: добавил ссылку на ещё один вариант, сделанный уже не из спортивного интересу, а для боевого применения. Метод должен быть практически универсальным: работает с датами, стандартными обёртками Boolean, String и т.д., полностью разруливает циклы и даже не боится наличия в хеше ключа hasOwnProperty.

Естественно, в твит (даже в два) уже не влезает, однако, думаю, что именно этот вариант я и буду использовать на практике.
Для чего нужно o.hasOwnProperty(i), если мы из него же и извлекаем эту i?
Чтобы, если нам дадут что-то посложнее простого хеша, клонировать только его свойства, а не свойства всех прототипов.
В стародавние времена люди змейку на ассемблере писали — кто компактней, а сейчас js :-) Люди не меняются.
Непонятно функционал для клона не включили в стандарт, хотя бы без рекурсии.
*Непонятно почему фунционал
Значит жопных место было столько, что проще было «забыть» )
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации