При передаче объектов в качестве параметров JavaScript передает их по ссылке и затрудняет создание локальных копий объектов.
var o = {}; (function(x){ var obj = x; obj.foo = 'foo'; obj.bar = 'bar'; })(o)
o
будет.foo
и.bar
.Это можно обойти путем клонирования; простой пример:
var o = {}; function Clone(x) { for(p in x) this[p] = (typeof(x[p]) == 'object')? new Clone(x[p]) : x[p]; } (function(x){ var obj = new Clone(x); obj.foo = 'foo'; obj.bar = 'bar'; })(o)
o
не будет.foo
или.bar
.
Вопрос
- Есть ли лучший способ передать объекты по значению, кроме создания локальной копии / клона?
javascript
vol7ron
источник
источник
Ответы:
На самом деле, нет.
В зависимости от того, что вам действительно нужно, одна из возможностей может заключаться в установке
o
в качестве прототипа нового объекта.var o = {}; (function(x){ var obj = Object.create( x ); obj.foo = 'foo'; obj.bar = 'bar'; })(o); alert( o.foo ); // undefined
Таким образом, никакие свойства, которые вы добавляете
obj
, не будут добавленыo
. Любые свойства, добавленныеobj
с тем же именем свойства, что и свойство в,o
будут затенятьo
свойство.Конечно, любые добавленные свойства
o
будут доступны из,obj
если они не затенены, и все объекты, которые естьo
в цепочке прототипов, будут видеть те же обновленияo
.Кроме того, если
obj
есть свойство, которое ссылается на другой объект, например массив, вам нужно обязательно затенять этот объект перед добавлением членов к объекту, в противном случае эти элементы будут добавленыobj
и будут совместно использоваться всеми объектами, которые естьobj
в цепочке прототипов.var o = { baz: [] }; (function(x){ var obj = Object.create( x ); obj.baz.push( 'new value' ); })(o); alert( o.baz[0] ); // 'new_value'
Здесь вы можете видеть, что, поскольку вы не затеняли массив в
baz
ono
с включеннымbaz
свойствомobj
,o.baz
массив изменяется.Поэтому вместо этого вам нужно сначала затенить его:
var o = { baz: [] }; (function(x){ var obj = Object.create( x ); obj.baz = []; obj.baz.push( 'new value' ); })(o); alert( o.baz[0] ); // undefined
источник
Object.create
в своем ответе, но я не хотел растягиваться, чтобы объяснить поверхностность текста ;-)var obj = new Object(x)
. Для меня, я думаю, этоnew Object(x)
будет работатьObject.create(x)
по умолчанию - интересноnew Object(x)
просто выплевывает тот же объект (как вы, наверное, заметили) . Было бы неплохо, если бы был родной способ клонирования. Не уверен, что в работе что-то есть.Посмотрите этот ответ https://stackoverflow.com/a/5344074/746491 .
Короче говоря,
JSON.parse(JSON.stringify(obj))
это быстрый способ скопировать ваши объекты, если ваши объекты могут быть сериализованы в json.источник
JSON
Is не включен и должен быть определен - с таким же успехом может быть более описательным с именем вродеClone
. Однако я подозреваю, что мое мнение может измениться в будущем, поскольку JSON в большей степени интегрирован в программное обеспечение, не основанное на браузере, такое как базы данных и IDEВот функция клонирования, которая будет выполнять глубокую копию объекта:
function clone(obj){ if(obj == null || typeof(obj) != 'object') return obj; var temp = new obj.constructor(); for(var key in obj) temp[key] = clone(obj[key]); return temp; }
Теперь вы можете использовать это так:
(function(x){ var obj = clone(x); obj.foo = 'foo'; obj.bar = 'bar'; })(o)
источник
Использовать
Object.assign()
Пример:
var a = {some: object}; var b = new Object; Object.assign(b, a); // b now equals a, but not by association.
Более чистый пример, который делает то же самое:
var a = {some: object}; var b = Object.assign({}, a); // Once again, b now equals a.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
источник
var b = Object.assign({}, a);
a
будут скопированы как ссылка.Вы немного запутались в том, как работают объекты в JavaScript. Ссылка на объект - это значение переменной. Нет несериализованного значения. Когда вы создаете объект, его структура сохраняется в памяти, а переменная, которой он был назначен, содержит ссылку на эту структуру.
Даже если то, что вы просите, было предоставлено в виде какой-то простой конструкции на родном языке, технически это все равно было бы клонированием.
На самом деле JavaScript - это просто передача по значению ... просто переданное значение может быть ссылкой на что-то.
источник
Использовать это
x = Object.create(x1);
x
иx1
будет два разных объекта, изменениеx
не изменитсяx1
источник
Javascript всегда передается по значению. В этом случае он передает копию ссылки
o
в анонимную функцию. Код использует копию ссылки, но изменяет единственный объект. Невозможно заставить javascript передавать что-либо, кроме значения.В этом случае вы хотите передать копию базового объекта. Клонирование объекта - единственный выход. Однако ваш метод клонирования нуждается в небольшом обновлении
function ShallowCopy(o) { var copy = Object.create(o); for (prop in o) { if (o.hasOwnProperty(prop)) { copy[prop] = o[prop]; } } return copy; }
источник
Для пользователей jQuery есть также способ сделать это простым способом, используя фреймворк. JQuery - это еще один способ сделать нашу жизнь немного проще.
var oShallowCopy = jQuery.extend({}, o); var oDeepCopy = jQuery.extend(true, {}, o);
Ссылки :
источник
На самом деле Javascript всегда передается по значению . Но поскольку ссылки на объекты являются значениями , объекты будут вести себя так, как будто они передаются по ссылке .
Поэтому для того , чтобы ходить вокруг этого, stringify объект и разобрать его обратно, как с помощью JSON. См. Пример кода ниже:
var person = { Name: 'John', Age: '21', Gender: 'Male' }; var holder = JSON.stringify(person); // value of holder is "{"Name":"John","Age":"21","Gender":"Male"}" // note that holder is a new string object var person_copy = JSON.parse(holder); // value of person_copy is { Name: 'John', Age: '21', Gender: 'Male' }; // person and person_copy now have the same properties and data // but are referencing two different objects
источник
Использование оператора распространения, например,
obj2 = { ...obj1 }
будет иметь одинаковые значения, но разные ссылкиисточник
let a = {value: "old"}
let b = [...a]
b.value = "new"
и будет{value: "old"}
, а будет{value: "new"}
. Но не получается когдаlet a = [{value: "old"}]
let b = [...a]
b[0].value = "new"
, а будет[{value: "new"}]
, а будет[{value: "new"}]
.Мне нужно было скопировать объект по значению (не по ссылке), и я нашел эту страницу полезной:
Каков наиболее эффективный способ глубокого клонирования объекта в JavaScript? . В частности, клонирование объекта с помощью следующего кода от Джона Ресига:
//Shallow copy var newObject = jQuery.extend({}, oldObject); // Deep copy var newObject = jQuery.extend(true, {}, oldObject);
источник
С синтаксисом ES6:
let obj = Object.assign({}, o);
источник
Object.assign
заключается в том, что он не выполняет глубокую копию.Если говорить об этом, то это просто причудливый, чрезмерно сложный прокси, но, может быть, с ним справятся Catch-All Proxies ?
var o = { a: 'a', b: 'b', func: function() { return 'func'; } }; var proxy = Proxy.create(handlerMaker(o), o); (function(x){ var obj = x; console.log(x.a); console.log(x.b); obj.foo = 'foo'; obj.bar = 'bar'; })(proxy); console.log(o.foo); function handlerMaker(obj) { return { getOwnPropertyDescriptor: function(name) { var desc = Object.getOwnPropertyDescriptor(obj, name); // a trapping proxy's properties must always be configurable if (desc !== undefined) { desc.configurable = true; } return desc; }, getPropertyDescriptor: function(name) { var desc = Object.getOwnPropertyDescriptor(obj, name); // not in ES5 // a trapping proxy's properties must always be configurable if (desc !== undefined) { desc.configurable = true; } return desc; }, getOwnPropertyNames: function() { return Object.getOwnPropertyNames(obj); }, getPropertyNames: function() { return Object.getPropertyNames(obj); // not in ES5 }, defineProperty: function(name, desc) { }, delete: function(name) { return delete obj[name]; }, fix: function() {} }; }
источник
Если вы используете lodash или
npm
, используйте функцию слияния lodash для глубокого копирования всех свойств объекта в новый пустой объект, например:var objectCopy = lodash.merge({}, originalObject);
https://lodash.com/docs#merge
https://www.npmjs.com/package/lodash.merge
источник