JavaScript: Как передать объект по значению?
-
При передаче объектов в качестве параметров 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
.
Вопрос
- Есть ли лучший способ передать объекты по значению, кроме создания локальной копии/клона?
Ответы
Ответ 1
Не совсем.
В зависимости от того, что вам действительно нужно, одной из возможностей может быть установка 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
имеет свойство, которое ссылается на другой объект, например Array, вам нужно будет затенять этот объект перед добавлением членов в объект, в противном случае эти члены будут добавлены в 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
на o
с помощью свойства 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
Ответ 2
Вот функция клонирования, которая будет выполнять глубокую копию объекта:
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)
Ответ 3
Проверьте этот ответ fooobar.com/questions/97/....
Короче говоря, JSON.parse(JSON.stringify(obj))
- быстрый способ копирования ваших объектов, если ваши объекты могут быть сериализованы для json.
Ответ 4
Вы немного смущены тем, как объекты работают в JavaScript. Ссылка на объект - это значение переменной. Нет неэтериализованной ценности. Когда вы создаете объект, его структура хранится в памяти, а переменная, которой она была назначена, содержит ссылку на эту структуру.
Даже если то, что вы просите, было предоставлено в какой-то простой конструкции на родном языке, все равно будет технически клонироваться.
JavaScript действительно просто передается по значению... это просто, что переданное значение может быть ссылкой на что-то.
Ответ 5
Используйте 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
Ответ 6
Javascript всегда проходит по значению. В этом случае он передает копию ссылки o
в анонимную функцию. Код использует копию ссылки, но она мутирует один объект. Невозможно сделать javascript-проход ничем, кроме значения.
В этом случае вы должны передать копию базового объекта. Клонирование объекта является единственным средством обращения. Ваш метод clone нуждается в обновлении, хотя
function ShallowCopy(o) {
var copy = Object.create(o);
for (prop in o) {
if (o.hasOwnProperty(prop)) {
copy[prop] = o[prop];
}
}
return copy;
}
Ответ 7
В качестве рассмотрения пользователям jQuery существует также способ сделать это простым способом с использованием фреймворка. Еще один способ, которым jQuery облегчает нашу жизнь.
var oShallowCopy = jQuery.extend({}, o);
var oDeepCopy = jQuery.extend(true, {}, o);
ссылки:
Ответ 8
Используйте этот
x = Object.create(x1);
x
и x1
будут два разных объекта, изменение в x
не изменится x1
Ответ 9
Мне нужно было скопировать объект по значению (без ссылки), и я нашел эту страницу полезной:
Каков наиболее эффективный способ глубокого клонирования объекта в JavaScript?. В частности, клонирование объекта с помощью следующего кода Джона Ресига:
//Shallow copy
var newObject = jQuery.extend({}, oldObject);
// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);
Ответ 10
Собственно, Javascript всегда передает значение. Но поскольку ссылки на объекты значения, объекты будут вести себя так, как будто они переданы по ссылке.
Итак, чтобы обойти это, подстроить объект и описать его обратно, используя 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
Ответ 11
Когда вы сворачиваетесь на него, это просто необычный слишком сложный прокси, но, возможно, 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 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 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() {}
};
}
Ответ 12
Если вы используете lodash или npm
, используйте функцию lodash merge, чтобы полностью скопировать все свойства объекта на новый пустой объект:
var objectCopy = lodash.merge({}, originalObject);
https://lodash.com/docs#merge
https://www.npmjs.com/package/lodash.merge
Ответ 13
С синтаксисом ES6:
let obj = Object.assign({}, o);