В документации jQuery.fn.on
есть хорошее объяснение.
Короче:
Обработчики событий привязаны только к выбранные в данный момент элементы; они должны существовать на странице, когда ваш код делает вызов
.on()
.Таким образом, в следующем примере
#dataTable tbody tr
должен существовать до генерации кода.$("#dataTable tbody tr").on("click", function(event){ console.log($(this).text()); });
Если на страницу вводится новый HTML-код, предпочтительнее использовать делегированные события для присоединения обработчика событий, как описано ниже.
Делегированные события имеют то преимущество, что они могут обрабатывать события от элементов потомков, которые будут добавлены в документ позже. Например, если таблица существует, но строки добавляются динамически с использованием кода, следующее будет обрабатывать ее:
$("#dataTable tbody").on("click", "tr", function(event){ console.log($(this).text()); });
В дополнение к их способности обрабатывать события на дочерних элементах, которые еще не созданы, другим преимуществом делегированных событий является их потенциал для гораздо более низких накладных расходов, когда необходимо контролировать многие элементы. В таблице данных с 1000 строками в
tbody
первый пример кода прикрепляет обработчик к 1000 элементам.Подход с делегированными событиями (второй пример кода) прикрепляет обработчик события только к одному элементу ,
tbody
, и событию нужно только выровнять один уровень (от щелчкаtr
доtbody
).Примечание. Делегированные события не работают для SVG .
Примечание. Это ответ на другой ответ, а не правильный ответ на этот вопрос. Если вы хотите быстро клонировать объекты, пожалуйста, следуйте советам Корбана в их ответе на этот вопрос.
Хочу отметить, что
.clone()
в jQuery только клонирует элементы DOM. Для клонирования объектов JavaScript вы бы сделали:// Shallow copy var newObject = jQuery.extend({}, oldObject); // Deep copy var newObject = jQuery.extend(true, {}, oldObject);
Более подробную информацию можно найти в документации jQuery .
Также хочу отметить что глубокая копия на самом деле намного умнее, чем показано выше, - она способна избежать многих ловушек (например, пытается глубоко расширить элемент DOM). Он часто используется в ядре jQuery и в плагинах.
Cloning
Объект всегда был предметом беспокойства в JS, но все это было до ES6, я перечисляю различные способы копирования объекта в JavaScript ниже, представьте, что у вас есть Объект ниже и вы хотите иметь глубокую копию что:
var obj = {a:1, b:2, c:3, d:4};
Существует несколько способов копирования этого объекта без изменения источника:
1) ES5 +, используя простую функцию для копирования:
function deepCopyObj(obj) {
if (null == obj || "object" != typeof obj) return obj;
if (obj instanceof Date) {
var copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
if (obj instanceof Array) {
var copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = cloneSO(obj[i]);
}
return copy;
}
if (obj instanceof Object) {
var copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj this object.");
}
2) ES5 +, используя JSON.parse и JSON.stringify.
var deepCopyObj = JSON.parse(JSON.stringify(obj));
3) AngularJs:
var deepCopyObj = angular.copy(obj);
4) jQuery:
var deepCopyObj = jQuery.extend(true, {}, obj);
5) UnderscoreJs & amp; Loadash:
var deepCopyObj = _.cloneDeep(obj); //latest version UndescoreJs makes shallow copy
Надеюсь, что эта помощь ...
Object.assign
делает не i> глубокую копию. Пример: var x = { a: { b: "c" } }; var y = Object.assign({}, x); x.a.b = "d"
. Если это была глубокая копия, y.a.b
все равно будет c
, но теперь она d
.
– kba
10 May 2017 в 15:52
Глубокая копия по производительности: ранжировано от лучшего к худшему
Глубоко скопируйте массив строк или чисел (один уровень - без указателей):
Когда массив содержит числа и строки - такие функции, как .slice (), .concat (), .splice (), оператор присваивания «=» и функция клона Underscore.js; будет делать глубокую копию элементов массива.
Если переназначение имеет самую высокую производительность:
var arr1 = ['a', 'b', 'c'];
var arr2 = arr1;
arr1 = ['a', 'b', 'c'];
И .slice () имеет лучшую производительность, чем .concat (), http://jsperf.com/duplicate-array-slice-vs-concat/3
var arr1 = ['a', 'b', 'c']; // Becomes arr1 = ['a', 'b', 'c']
var arr2a = arr1.slice(0); // Becomes arr2a = ['a', 'b', 'c'] - deep copy
var arr2b = arr1.concat(); // Becomes arr2b = ['a', 'b', 'c'] - deep copy
Глубоко копировать массив объектов (два или более уровней - указатели ссылок):
var arr1 = [{object:'a'}, {object:'b'}];
Напишите пользовательскую функцию (имеет более высокую производительность, чем $ .extend () или JSON.parse):
function copy(o) {
var out, v, key;
out = Array.isArray(o) ? [] : {};
for (key in o) {
v = o[key];
out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
}
return out;
}
copy(arr1);
Используйте сторонние служебные функции:
$.extend(true, [], arr1); // Jquery Extend
JSON.parse(arr1);
_.cloneDeep(arr1); // Lo-dash
Там, где $ .extend jQuery имеет лучшую производительность:
out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
– josi
1 February 2018 в 17:53
Ознакомиться с этим эталоном: http://jsben.ch/#/bWfk9
В моих предыдущих тестах, где скорость была главной проблемой, я нашел
JSON.parse(JSON.stringify(obj))
- самый быстрый способ глубокого клонирования объекта (он выдает jQuery.extend с установленным значением глубокого флага на 10-20%).
jQuery.extend довольно быстро, когда для флага глубокого значения установлено значение false (мелкий клон). Это хороший вариант, поскольку он включает некоторую дополнительную логику для проверки типов и не копирует неопределенные свойства и т. Д., Но это также немного замедлит вас.
Если вам известна структура объекты, которые вы пытаетесь клонировать или можете избежать глубоких вложенных массивов, вы можете написать простой цикл for (var i in obj)
, чтобы клонировать ваш объект при проверке hasOwnProperty, и он будет намного быстрее, чем jQuery.
Наконец, если вы пытаясь клонировать известную структуру объекта в горячем цикле, вы можете получить МНОГО БОЛЬШЕ БОЛЬШЕ ПРОИЗВОДИТЕЛЬНОСТИ, просто вставив процедуру клонирования и вручную создав объект.
Механизмы слежения за JavaScript присасываются при оптимизации циклов for..in
и проверка hasOwnProperty также замедлит вас. Ручной клон, когда скорость является абсолютной необходимостью.
var clonedObject = {
knownProp: obj.knownProp,
..
}
Остерегайтесь использования метода JSON.parse(JSON.stringify(obj))
на объектах Date
- JSON.stringify(new Date())
возвращает строковое представление даты в формате ISO, которое JSON.parse()
не обращается обратно к объекту Date
. См. этот ответ для получения дополнительной информации .
Кроме того, обратите внимание, что в Chrome 65, по крайней мере, нативный клонирование не подходит. Согласно этот JSPerf , выполняющий собственное клонирование, создавая новую функцию, почти на 800 раз медленнее, чем использование JSON.stringify, которое невероятно быстро распространяется по всем направлениям.
keys
из вашего object
, который имеет functions
в качестве своих значений, потому что JSON
не поддерживает функции.
– Karlen Kishmiryan
29 May 2015 в 09:52
JSON.parse(JSON.stringify(obj))
в Date Objects также преобразует дату в UTC в строковое представление в формате ISO8601 .
– dnlgmzddr
30 July 2015 в 21:37
Я обычно использую var newObj = JSON.parse( JSON.stringify(oldObje) );
, но вот более правильный способ:
var o = {};
var oo = Object.create(o);
(o === oo); // => false
Смотреть устаревшие браузеры!
from.constructor
- Date
. Как будет проведен третий тест if
, когда 2-й тест if
будет успешным и, заставить функцию вернуться (поскольку Date != Object && Date != Array
)?
– Adam McKee
1 September 2015 в 02:10
const defaultFoo = { a: { b: 123 } };
вы можете пойти const defaultFoo = () => ({ a: { b: 123 } };
, и ваша проблема решена. Однако на самом деле это не ответ на вопрос. Это могло бы иметь больше смысла в качестве комментария к вопросу, а не полного ответа.
– Josh from Qaribou
6 February 2017 в 15:25
Object.create
не требуется создание копии объекта, вместо этого он использует старый объект в качестве прототипа для клона
– 16kb
22 June 2018 в 01:07
Крокфорд предлагает (и я предпочитаю) использовать эту функцию:
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
var newObject = object(oldObject);
Он краток, работает как ожидалось, и вам не нужна библиотека.
EDIT :
Это полиполк для Object.create
, поэтому вы также можете использовать это.
var newObject = Object.create(oldObject);
ПРИМЕЧАНИЕ. Если вы используете часть этого, у вас могут быть проблемы с некоторой итерацией кто использует hasOwnProperty
. Потому что create
создает новый пустой объект, который наследует oldObject
. Но это все еще полезно и практично для клонирования объектов.
Например, если oldObject.a = 5;
newObject.a; // is 5
, но:
oldObject.hasOwnProperty(a); // is true
newObject.hasOwnProperty(a); // is false
var extendObj = function(childObj, parentObj) { var tmpObj = function () {} tmpObj.prototype = parentObj.prototype; childObj.prototype = new tmpObj(); childObj.prototype.constructor = childObj; };
... davidshariff.com/blog/javascript-inheritance-patterns
– Cody
24 April 2014 в 19:32
Lodash имеет хороший метод _. cloneDeep (value) :
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
.clone(...)
библиотеки коммунальных услуг. Каждая основная библиотека будет иметь их, и повторяющиеся краткие не-подробные ответы не будут полезны большинству посетителей, которые не будут использовать эту конкретную библиотеку.
– Jeremy
7 April 2016 в 17:23
_.merge({}, objA)
. Если только lodash не мутировал объекты в первую очередь, тогда функция clone
не понадобилась.
– Rebs
27 February 2017 в 01:48
Только когда вы можете использовать ECMAScript 6 или транспилеры .
Особенности:
Код:
function clone(target, source){
for(let key in source){
// Use getOwnPropertyDescriptor instead of source[key] to prevent from trigering setter/getter.
let descriptor = Object.getOwnPropertyDescriptor(source, key);
if(descriptor.value instanceof String){
target[key] = new String(descriptor.value);
}
else if(descriptor.value instanceof Array){
target[key] = clone([], descriptor.value);
}
else if(descriptor.value instanceof Object){
let prototype = Reflect.getPrototypeOf(descriptor.value);
let cloneObject = clone({}, descriptor.value);
Reflect.setPrototypeOf(cloneObject, prototype);
target[key] = cloneObject;
}
else {
Object.defineProperty(target, key, descriptor);
}
}
let prototype = Reflect.getPrototypeOf(source);
Reflect.setPrototypeOf(target, prototype);
return target;
}
// obj target object, vals source object
var setVals = function (obj, vals) {
if (obj && vals) {
for (var x in vals) {
if (vals.hasOwnProperty(x)) {
if (obj[x] && typeof vals[x] === 'object') {
obj[x] = setVals(obj[x], vals[x]);
} else {
obj[x] = vals[x];
}
}
}
}
return obj;
};
У меня есть два хороших ответа в зависимости от того, должна ли ваша цель клонировать «простой старый объект JavaScript» или нет.
Предположим также, что вы намерены создать полный клон без ссылок на прототипы назад к исходному объекту. Если вас не интересует полный клон, вы можете использовать многие из подпрограмм Object.clone (), предоставленные в некоторых других ответах (шаблон Крокфорда).
Для простых старых объектов JavaScript надежный и надежный способ клонирования объекта в современных средах выполнения довольно просто:
var clone = JSON.parse(JSON.stringify(obj));
Обратите внимание, что исходный объект должен быть чистым объектом JSON. Это означает, что все его вложенные свойства должны быть скалярами (например, логическими, строковыми, массивными, объектными и т. Д.). Любые функции или специальные объекты, такие как RegExp или Date, не будут клонированы.
Является ли он эффективным? Черт возьми. Мы пробовали все виды методов клонирования, и это работает лучше всего. Я уверен, что какой-нибудь ниндзя может вызвать более быстрый метод. Но я подозреваю, что мы говорим о предельных выигрышах.
Этот подход просто прост и прост в реализации. Включите его в функцию удобства, и если вам действительно нужно выжать некоторый выигрыш, идите позже.
Теперь, для не-простых объектов JavaScript, нет простого ответа. На самом деле не может быть из-за динамического характера функций JavaScript и состояния внутреннего объекта. Глубокое клонирование структуры JSON с функциями внутри требует, чтобы вы воссоздали эти функции и их внутренний контекст. И JavaScript просто не имеет стандартного способа сделать это.
Правильный способ сделать это еще раз - это метод удобства, который вы декларируете и повторно используете в своем коде. Метод удобства может быть наделен некоторым пониманием ваших собственных объектов, чтобы вы могли правильно воссоздать график в новом объекте.
Мы пишем наш собственный, но лучший общий подход. см. здесь:
http://davidwalsh.name/javascript-clone
Это правильная идея. Автор (Дэвид Уолш) прокомментировал клонирование обобщенных функций.
Основная идея заключается в том, что вам нужно специально обработать инстанцирование ваших функций (или прототипных классов, если можно так выразиться) тип основы. Здесь он предоставил несколько примеров для RegExp и Date.
Этот код не только краткий, но и очень читабельный. Это довольно легко расширить.
Это эффективно? Черт возьми. Учитывая, что цель состоит в том, чтобы создать настоящий клон с глубокой копией, вам придется ходить по членам графа исходного объекта. С помощью этого подхода вы можете точно настроить, какие дочерние элементы обрабатывать и как вручную обрабатывать настраиваемые типы.
Итак, вы идете. Два подхода. На мой взгляд, обе эффективны.
Если вы используете его, библиотека Underscore.js имеет метод clone .
var newObject = _.clone(oldObject);
.clone(...)
библиотеки коммунальных услуг. Каждая основная библиотека будет иметь их, и повторяющиеся краткие не-подробные ответы не будут полезны большинству посетителей, которые не будут использовать эту конкретную библиотеку.
– Jeremy
7 April 2016 в 17:25
Существует библиотека (так называемый «клон») , что делает это довольно хорошо. Он обеспечивает наиболее полное рекурсивное клонирование / копирование произвольных объектов, о которых я знаю. Он также поддерживает циклические ссылки, которые еще не покрыты другими ответами.
Вы можете найти его на npm . Его можно использовать как для браузера, так и для Node.js.
Вот пример того, как его использовать:
Установите его с помощью
npm install clone
или упакуйте его с помощью Ender .
ender build clone [...]
Вы также можете загрузить исходный код вручную.
Затем вы можете использовать его в своем исходном коде.
var clone = require('clone');
var a = { foo: { bar: 'baz' } }; // inital value of a
var b = clone(a); // clone a -> b
a.foo.bar = 'foo'; // change a
console.log(a); // { foo: { bar: 'foo' } }
console.log(b); // { foo: { bar: 'baz' } }
(Отказ от ответственности: я являюсь автором библиотеки.)
JSON.parse(JSON.stringify(obj))
?
– pkyeck
1 December 2016 в 17:03
Просто потому, что я не видел AngularJS и думал, что люди захотят узнать ...
angular.copy
также предоставляет метод глубоких копирующих объектов и массивов.
angular.extend({},obj);
– Galvani
21 September 2016 в 09:07
jQuery.extend
и angular.extend
являются неглубокими копиями. angular.copy
- это глубокая копия.
– Dan Atkinson
15 October 2016 в 18:41
Неглубокая копия с одним слоем ( 5-е издание ECMAScript ):
var origin = { foo : {} };
var copy = Object.keys(origin).reduce(function(c,k){c[k]=origin[k];return c;},{});
console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true
И мелкая копия с одним слоем ( ECMAScript 6-е издание , 2015 ):
var origin = { foo : {} };
var copy = Object.assign({}, origin);
console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true
Object.keys
, пропускает неперечислимые и унаследованные свойства. Кроме того, он теряет дескрипторы свойств, выполняя прямое назначение.
– Matt Bierner
23 November 2013 в 19:51
До сих пор нет идеального оператора глубокого клонирования для объектов типа массива. Как видно из приведенного ниже кода, клон JQuery Джона Ресига превращает массивы с нечисловыми свойствами в объекты, которые не являются массивами, а клонирование Cloner от RegDwight снижает нечисловые свойства. Следующие тесты иллюстрируют эти моменты в нескольких браузерах:
function jQueryClone(obj) {
return jQuery.extend(true, {}, obj)
}
function JSONClone(obj) {
return JSON.parse(JSON.stringify(obj))
}
var arrayLikeObj = [[1, "a", "b"], [2, "b", "a"]];
arrayLikeObj.names = ["m", "n", "o"];
var JSONCopy = JSONClone(arrayLikeObj);
var jQueryCopy = jQueryClone(arrayLikeObj);
alert("Is arrayLikeObj an array instance?" + (arrayLikeObj instanceof Array) +
"\nIs the jQueryClone an array instance? " + (jQueryCopy instanceof Array) +
"\nWhat are the arrayLikeObj names? " + arrayLikeObj.names +
"\nAnd what are the JSONClone names? " + JSONCopy.names)
Предполагая, что у вас есть только переменные, а не какие-либо функции в вашем объекте, вы можете просто использовать:
var newObject = JSON.parse(JSON.stringify(oldObject));
JSON
реализован в собственном коде (в большинстве браузеров), это будет значительно быстрее, чем использование любого другого решения для глубокого копирования на основе javascript, и может иногда i> быть быстрее, чем на основе javascript (см. jsperf.com/cloning-an-object/79 ).
– MiJyn
4 July 2013 в 08:42
Date
объекты, которые хранятся внутри объекта, преобразуя их в строчную форму.
– fstab
21 August 2014 в 13:51
Это то, что я использую:
function cloneObject(obj) {
var clone = {};
for(var i in obj) {
if(typeof(obj[i])=="object" && obj[i] != null)
clone[i] = cloneObject(obj[i]);
else
clone[i] = obj[i];
}
return clone;
}
cloneObject({ name: null })
= & gt; {"name":{}}
– Niyaz
27 February 2013 в 16:36
typeof null > "object"
, но Object.keys(null) > TypeError: Requested keys of a value that is not an object.
изменяет условие на if(typeof(obj[i])=="object" && obj[i]!=null)
– Vitim.us
16 April 2013 в 17:42
Следующие создаются два экземпляра одного и того же объекта. Я нашел его и использую его в настоящее время. Он прост и удобен.
var objToCreate = JSON.parse(JSON.stringify(cloneThis));
Метод Object.assign
является частью стандарта ECMAScript 2015 (ES6) и делает именно то, что вам нужно.
var clone = Object.assign({}, obj);
Метод Object.assign () используется для копирования значений всех перечислимых собственных свойств из одного или нескольких исходных объектов в целевой объект.
Полипол для поддержки старых браузеров:
if (!Object.assign) { Object.defineProperty(Object, 'assign', { enumerable: false, configurable: true, writable: true, value: function(target) { 'use strict'; if (target === undefined || target === null) { throw new TypeError('Cannot convert first argument to object'); } var to = Object(target); for (var i = 1; i < arguments.length; i++) { var nextSource = arguments[i]; if (nextSource === undefined || nextSource === null) { continue; } nextSource = Object(nextSource); var keysArray = Object.keys(nextSource); for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) { var nextKey = keysArray[nextIndex]; var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey); if (desc !== undefined && desc.enumerable) { to[nextKey] = nextSource[nextKey]; } } } return to; } }); }
Вот комплексный метод clone (), который может клонировать любой объект JavaScript. Он обрабатывает почти все случаи:
function clone(src, deep) {
var toString = Object.prototype.toString;
if (!src && typeof src != "object") {
// Any non-object (Boolean, String, Number), null, undefined, NaN
return src;
}
// Honor native/custom clone methods
if (src.clone && toString.call(src.clone) == "[object Function]") {
return src.clone(deep);
}
// DOM elements
if (src.nodeType && toString.call(src.cloneNode) == "[object Function]") {
return src.cloneNode(deep);
}
// Date
if (toString.call(src) == "[object Date]") {
return new Date(src.getTime());
}
// RegExp
if (toString.call(src) == "[object RegExp]") {
return new RegExp(src);
}
// Function
if (toString.call(src) == "[object Function]") {
//Wrap in another method to make sure == is not true;
//Note: Huge performance issue due to closures, comment this :)
return (function(){
src.apply(this, arguments);
});
}
var ret, index;
//Array
if (toString.call(src) == "[object Array]") {
//[].slice(0) would soft clone
ret = src.slice();
if (deep) {
index = ret.length;
while (index--) {
ret[index] = clone(ret[index], true);
}
}
}
//Object
else {
ret = src.constructor ? new src.constructor() : {};
for (var prop in src) {
ret[prop] = deep
? clone(src[prop], true)
: src[prop];
}
}
return ret;
};
var clone = function() {
var newObj = (this instanceof Array) ? [] : {};
for (var i in this) {
if (this[i] && typeof this[i] == "object") {
newObj[i] = this[i].clone();
}
else
{
newObj[i] = this[i];
}
}
return newObj;
};
Object.defineProperty( Object.prototype, "clone", {value: clone, enumerable: false});
Вот версия ответа ConroyP выше, которая работает, даже если у конструктора требуются параметры:
//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
object_create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
function deepCopy(obj) {
if(obj == null || typeof(obj) !== 'object'){
return obj;
}
//make sure the returned object has the same prototype as the original
var ret = object_create(obj.constructor.prototype);
for(var key in obj){
ret[key] = deepCopy(obj[key]);
}
return ret;
}
Эта функция также доступна в моей библиотеке simpleoo .
Редактировать:
Вот более надежная версия (благодаря Джастину МакКэндлесу, теперь это также поддерживает циклические ссылки):
/**
* Deep copy an object (make copies of all its object properties, sub-properties, etc.)
* An improved version of http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
* that doesn't break if the constructor has required parameters
*
* It also borrows some code from http://stackoverflow.com/a/11621004/560114
*/
function deepCopy(src, /* INTERNAL */ _visited, _copiesVisited) {
if(src === null || typeof(src) !== 'object'){
return src;
}
//Honor native/custom clone methods
if(typeof src.clone == 'function'){
return src.clone(true);
}
//Special cases:
//Date
if(src instanceof Date){
return new Date(src.getTime());
}
//RegExp
if(src instanceof RegExp){
return new RegExp(src);
}
//DOM Element
if(src.nodeType && typeof src.cloneNode == 'function'){
return src.cloneNode(true);
}
// Initialize the visited objects arrays if needed.
// This is used to detect cyclic references.
if (_visited === undefined){
_visited = [];
_copiesVisited = [];
}
// Check if this object has already been visited
var i, len = _visited.length;
for (i = 0; i < len; i++) {
// If so, get the copy we already made
if (src === _visited[i]) {
return _copiesVisited[i];
}
}
//Array
if (Object.prototype.toString.call(src) == '[object Array]') {
//[].slice() by itself would soft clone
var ret = src.slice();
//add it to the visited array
_visited.push(src);
_copiesVisited.push(ret);
var i = ret.length;
while (i--) {
ret[i] = deepCopy(ret[i], _visited, _copiesVisited);
}
return ret;
}
//If we've reached here, we have a regular object
//make sure the returned object has the same prototype as the original
var proto = (Object.getPrototypeOf ? Object.getPrototypeOf(src): src.__proto__);
if (!proto) {
proto = src.constructor.prototype; //this line would probably only be reached by very old browsers
}
var dest = object_create(proto);
//add this object to the visited array
_visited.push(src);
_copiesVisited.push(dest);
for (var key in src) {
//Note: this does NOT preserve ES5 property attributes like 'writable', 'enumerable', etc.
//For an example of how this could be modified to do so, see the singleMixin() function
dest[key] = deepCopy(src[key], _visited, _copiesVisited);
}
return dest;
}
//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
object_create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}
Если не было встроенного, вы можете попробовать:
function clone(obj) {
if (obj === null || typeof(obj) !== 'object' || 'isActiveClone' in obj)
return obj;
if (obj instanceof Date)
var temp = new obj.constructor(); //or new Date(obj);
else
var temp = obj.constructor();
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
obj['isActiveClone'] = null;
temp[key] = clone(obj[key]);
delete obj['isActiveClone'];
}
}
return temp;
}
Хорошо, если вы используете угловой, вы тоже можете это сделать
var newObject = angular.copy(oldObject);
HTML5 определяет внутренний «структурированный» алгоритм клонирования , который может создавать глубокие клоны объектов. Он по-прежнему ограничен определенными встроенными типами, но в дополнение к нескольким типам, поддерживаемым JSON, он также поддерживает Dates, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, редкие массивы, Typed Arrays , и, вероятно, больше в будущем. Он также сохраняет ссылки в клонированных данных, позволяя ему поддерживать циклические и рекурсивные структуры, которые могут вызывать ошибки для JSON.
history.pushState()
и history.replaceState()
оба синхронно устанавливают history.state
в структурированный клон их первого аргумента. Немного странно, но это работает. Я обновляю свой ответ.
– Jeremy
6 May 2013 в 04:11
function clone(obj)
{ var clone = {};
clone.prototype = obj.prototype;
for (property in obj) clone[property] = obj[property];
return clone;
}
Это, как правило, не самое эффективное решение, но оно делает то, что мне нужно. Простые тестовые примеры ниже ...
function clone(obj, clones) {
// Makes a deep copy of 'obj'. Handles cyclic structures by
// tracking cloned obj's in the 'clones' parameter. Functions
// are included, but not cloned. Functions members are cloned.
var new_obj,
already_cloned,
t = typeof obj,
i = 0,
l,
pair;
clones = clones || [];
if (obj === null) {
return obj;
}
if (t === "object" || t === "function") {
// check to see if we've already cloned obj
for (i = 0, l = clones.length; i < l; i++) {
pair = clones[i];
if (pair[0] === obj) {
already_cloned = pair[1];
break;
}
}
if (already_cloned) {
return already_cloned;
} else {
if (t === "object") { // create new object
new_obj = new obj.constructor();
} else { // Just use functions as is
new_obj = obj;
}
clones.push([obj, new_obj]); // keep track of objects we've cloned
for (key in obj) { // clone object members
if (obj.hasOwnProperty(key)) {
new_obj[key] = clone(obj[key], clones);
}
}
}
}
return new_obj || obj;
}
Тест циклического массива ...
a = []
a.push("b", "c", a)
aa = clone(a)
aa === a //=> false
aa[2] === a //=> false
aa[2] === a[2] //=> false
aa[2] === aa //=> true
Функциональный тест ...
f = new Function
f.a = a
ff = clone(f)
ff === f //=> true
ff.a === a //=> false
Я не согласен с ответом с наибольшим количеством голосов здесь . Рекурсивный глубокий клон намного быстрее, чем упомянутый подход JSON.parse (JSON.stringify (obj)) .
И вот функция для быстрой справки:
function cloneDeep (o) {
let newO
let i
if (typeof o !== 'object') return o
if (!o) return o
if (Object.prototype.toString.apply(o) === '[object Array]') {
newO = []
for (i = 0; i < o.length; i += 1) {
newO[i] = cloneDeep(o[i])
}
return newO
}
newO = {}
for (i in o) {
if (o.hasOwnProperty(i)) {
newO[i] = cloneDeep(o[i])
}
}
return newO
}
if(o instanceof Date) return new Date(o.valueOf());
после проверки на нуль `
– Luis
21 August 2017 в 22:53
Я знаю, что это старый пост, но я подумал, что это может помочь кому-то, кто спотыкается.
Пока вы не назначаете объект ни к чему, он не поддерживает ссылка в памяти. Поэтому, чтобы создать объект, который вы хотите разделить между другими объектами, вам нужно создать такую фабрику:
var a = function(){
return {
father:'zacharias'
};
},
b = a(),
c = a();
c.father = 'johndoe';
alert(b.father);
from.constructor
- Date
. Как будет проведен третий тест if
, когда 2-й тест if
будет успешным и, заставить функцию вернуться (поскольку Date != Object && Date != Array
)?
– Adam McKee
1 September 2015 в 02:10
const defaultFoo = { a: { b: 123 } };
вы можете пойти const defaultFoo = () => ({ a: { b: 123 } };
, и ваша проблема решена. Однако на самом деле это не ответ на вопрос. Это могло бы иметь больше смысла в качестве комментария к вопросу, а не полного ответа.
– Josh from Qaribou
6 February 2017 в 15:25
Код:
// extends 'from' object with members from 'to'. If 'to' is null, a deep clone of 'from' is returned
function extend(from, to)
{
if (from == null || typeof from != "object") return from;
if (from.constructor != Object && from.constructor != Array) return from;
if (from.constructor == Date || from.constructor == RegExp || from.constructor == Function ||
from.constructor == String || from.constructor == Number || from.constructor == Boolean)
return new from.constructor(from);
to = to || new from.constructor();
for (var name in from)
{
to[name] = typeof to[name] == "undefined" ? extend(from[name], null) : to[name];
}
return to;
}
Тест:
var obj =
{
date: new Date(),
func: function(q) { return 1 + q; },
num: 123,
text: "asdasd",
array: [1, "asd"],
regex: new RegExp(/aaa/i),
subobj:
{
num: 234,
text: "asdsaD"
}
}
var clone = extend(obj);
from.constructor
- Date
. Как будет проведен третий тест if
, когда 2-й тест if
будет успешным и, заставить функцию вернуться (поскольку Date != Object && Date != Array
)?
– Adam McKee
1 September 2015 в 02:10
.clone()
, который не является правильным кодом для использования в этом контексте). К сожалению, этот вопрос прошел через столько изменений, что первоначальная дискуссия уже не очевидна! Пожалуйста, просто следуйте советам Корбана и напишите цикл или скопируйте свойства непосредственно новому объекту, если вам нужна скорость. Или испытайте это для себя! – John Resig 21 January 2014 в 05:37