Ðдно из ÑÑндаменÑалÑнÑÑ Ð¾ÑлиÑий обÑекÑов Ð¾Ñ Ð¿ÑимиÑивов заклÑÑаеÑÑÑ Ð² Ñом, ÑÑо обÑекÑÑ Ñ ÑанÑÑÑÑ Ð¸ копиÑÑÑÑÑÑ Â«Ð¿Ð¾ ÑÑÑлке», Ñогда как пÑимиÑивнÑе знаÑениÑ: ÑÑÑоки, ÑиÑла, логиÑеÑкие знаÑÐµÐ½Ð¸Ñ Ð¸ Ñ.д. â вÑегда копиÑÑÑÑÑÑ Â«ÐºÐ°Ðº Ñелое знаÑение».
ÐÑо легко понÑÑÑ, еÑли Ð¼Ñ Ð½ÐµÐ¼Ð½Ð¾Ð³Ð¾ заглÑнем под ÐºÐ°Ð¿Ð¾Ñ Ñого, ÑÑо пÑоиÑÑ Ð¾Ð´Ð¸Ñ, когда Ð¼Ñ ÐºÐ¾Ð¿Ð¸ÑÑем знаÑение.
ÐавайÑе наÑнÑм Ñ Ð¿ÑимиÑива, Ñакого как ÑÑÑока.
ÐдеÑÑ Ð¼Ñ Ð¿Ð¾Ð¼ÐµÑаем ÐºÐ¾Ð¿Ð¸Ñ message во phrase:
let message = "ÐÑивеÑ!";
let phrase = message;
Ð ÑезÑлÑÑаÑе Ð¼Ñ Ð¸Ð¼ÐµÐµÐ¼ две незавиÑимÑе пеÑеменнÑе, ÐºÐ°Ð¶Ð´Ð°Ñ Ð¸Ð· коÑоÑÑÑ
Ñ
ÑÐ°Ð½Ð¸Ñ ÑÑÑÐ¾ÐºÑ "ÐÑивеÑ!".
Ðполне оÑевиднÑй ÑезÑлÑÑаÑ, не Ñак ли?
ÐбÑекÑÑ Ð²ÐµÐ´ÑÑ ÑÐµÐ±Ñ Ð¸Ð½Ð°Ñе.
ÐеÑеменнаÑ, коÑоÑой пÑиÑвоен обÑекÑ, Ñ ÑÐ°Ð½Ð¸Ñ Ð½Ðµ Ñам обÑекÑ, а его «адÑÐµÑ Ð² памÑÑи» â дÑÑгими Ñловами, «ÑÑÑлкÑ» на него.
ÐавайÑе ÑаÑÑмоÑÑим пÑÐ¸Ð¼ÐµÑ Ñакой пеÑеменной:
let user = {
name: "John"
};
Ð Ð²Ð¾Ñ ÐºÐ°Ðº ÑÑо на Ñамом деле Ñ ÑаниÑÑÑ Ð² памÑÑи:
ÐбÑÐµÐºÑ Ñ
ÑаниÑÑÑ Ð³Ð´Ðµ-Ñо в памÑÑи (ÑпÑава Ð¾Ñ Ð¸Ð·Ð¾Ð±ÑажениÑ), в Ñо вÑÐµÐ¼Ñ ÐºÐ°Ðº пеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ user (Ñлева) Ð¸Ð¼ÐµÐµÑ Ð»Ð¸ÑÑ Â«ÑÑÑлкÑ» на него.
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ дÑмаÑÑ Ð¾ пеÑеменной обÑекÑа, Ñакой как user, как о лиÑÑе бÑмаги Ñ Ð°Ð´ÑеÑом обÑекÑа на нем.
Ðогда Ð¼Ñ Ð²ÑполнÑем дейÑÑÐ²Ð¸Ñ Ñ Ð¾Ð±ÑекÑом, к пÑимеÑÑ, беÑÑм ÑвойÑÑво user.name, движок JavaScript пÑоÑмаÑÑÐ¸Ð²Ð°ÐµÑ Ñо, ÑÑо наÑ
одиÑÑÑ Ð¿Ð¾ ÑÑÐ¾Ð¼Ñ Ð°Ð´ÑеÑÑ, и вÑполнÑÐµÑ Ð¾Ð¿ÐµÑаÑÐ¸Ñ Ñ Ñамим обÑекÑом.
ТепеÑÑ Ð²Ð¾Ñ Ð¿Ð¾ÑÐµÐ¼Ñ ÑÑо важно.
ÐÑи копиÑовании пеÑеменной обÑекÑа копиÑÑеÑÑÑ ÑÑÑлка, но Ñам обÑÐµÐºÑ Ð½Ðµ дÑблиÑÑеÑÑÑ.
ÐапÑимеÑ:
let user = { name: "John" };
let admin = user; // копиÑÑеÑÑÑ ÑÑÑлка
ТепеÑÑ Ñ Ð½Ð°Ñ ÐµÑÑÑ Ð´Ð²Ðµ пеÑеменнÑе, ÐºÐ°Ð¶Ð´Ð°Ñ Ð¸Ð· коÑоÑÑÑ ÑодеÑÐ¶Ð¸Ñ ÑÑÑÐ»ÐºÑ Ð½Ð° один и ÑÐ¾Ñ Ð¶Ðµ обÑекÑ:
Ðак Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе видеÑÑ, вÑе еÑÑ ÐµÑÑÑ Ð¾Ð´Ð¸Ð½ обÑекÑ, но ÑепеÑÑ Ñ Ð´Ð²ÑÐ¼Ñ Ð¿ÐµÑеменнÑми, коÑоÑÑе ÑÑÑлаÑÑÑÑ Ð½Ð° него.
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ иÑполÑзоваÑÑ Ð»ÑбÑÑ Ð¿ÐµÑеменнÑÑ Ð´Ð»Ñ Ð´Ð¾ÑÑÑпа к обÑекÑÑ Ð¸ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÐµÐ³Ð¾ ÑодеÑжимого:
let user = { name: 'John' };
let admin = user;
admin.name = 'Pete'; // изменено по ÑÑÑлке из пеÑеменной "admin"
alert(user.name); // 'Pete', Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²Ð¸Ð´Ð½Ñ Ð¿Ð¾ ÑÑÑлке из пеÑеменной "user"
ÐÑо как еÑли Ð±Ñ Ñ Ð½Ð°Ñ Ð±Ñл ÑкаÑÑик Ñ Ð´Ð²ÑÐ¼Ñ ÐºÐ»ÑÑами, и Ð¼Ñ Ð¸ÑполÑзовали один из ниÑ
(admin), ÑÑÐ¾Ð±Ñ Ð²Ð¾Ð¹Ñи в него и внеÑÑи изменениÑ. РзаÑем, еÑли Ð¼Ñ Ð¿Ð¾Ð·Ð¶Ðµ иÑполÑзÑем дÑÑгой клÑÑ (user), Ð¼Ñ Ð²Ñе Ñавно оÑкÑÑваем ÑÐ¾Ñ Ð¶Ðµ ÑкаÑÑик и можем полÑÑиÑÑ Ð´Ð¾ÑÑÑп к изменÑÐ½Ð½Ð¾Ð¼Ñ ÑодеÑжимомÑ.
СÑавнение по ÑÑÑлке
Ðва обÑекÑа ÑÐ°Ð²Ð½Ñ ÑолÑко в Ñом ÑлÑÑае, еÑли ÑÑо один и ÑÐ¾Ñ Ð¶Ðµ обÑекÑ.
ÐапÑимеÑ, здеÑÑ a и b ÑÑÑлаÑÑÑÑ Ð½Ð° один и ÑÐ¾Ñ Ð¶Ðµ обÑекÑ, поÑÑÐ¾Ð¼Ñ Ð¾Ð½Ð¸ ÑавнÑ:
let a = {};
let b = a; // копиÑование по ÑÑÑлке
alert( a == b ); // true, обе пеÑеменнÑе ÑÑÑлаÑÑÑÑ Ð½Ð° один и ÑÐ¾Ñ Ð¶Ðµ обÑекÑ
alert( a === b ); // true
РздеÑÑ Ð´Ð²Ð° незавиÑимÑÑ Ð¾Ð±ÑекÑа не ÑавнÑ, даже еÑли они вÑглÑдÑÑ Ð¾Ð´Ð¸Ð½Ð°ÐºÐ¾Ð²Ð¾ (оба пÑÑÑÑ):
let a = {};
let b = {}; // два незавиÑимÑÑ
обÑекÑа
alert( a == b ); // false
ÐÐ»Ñ ÑÑавнений Ñипа obj1 > obj2 или Ð´Ð»Ñ ÑÑÐ°Ð²Ð½ÐµÐ½Ð¸Ñ Ñ Ð¿ÑимиÑивом obj == 5 обÑекÑÑ Ð¿ÑеобÑазÑÑÑÑÑ Ð² пÑимиÑивÑ. ÐÑÐµÐ½Ñ ÑкоÑо Ð¼Ñ Ð¸Ð·ÑÑим, как ÑабоÑаÑÑ Ð¿ÑеобÑÐ°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±ÑекÑов, но, по пÑавде говоÑÑ, Ñакие ÑÑÐ°Ð²Ð½ÐµÐ½Ð¸Ñ ÑÑебÑÑÑÑÑ Ð¾ÑÐµÐ½Ñ Ñедко и обÑÑно они поÑвлÑÑÑÑÑ Ð² ÑезÑлÑÑаÑе оÑибок пÑогÑаммиÑÑа.
ÐлониÑование и обÑединение, Object.assign
ÐÑак, копиÑование обÑекÑной пеÑеменной ÑоздаÑÑ ÐµÑÑ Ð¾Ð´Ð½Ñ ÑÑÑÐ»ÐºÑ Ð½Ð° ÑÐ¾Ñ Ð¶Ðµ обÑекÑ.
Ðо ÑÑо, еÑли нам вÑÑ Ð¶Ðµ нÑжно дÑблиÑоваÑÑ Ð¾Ð±ÑекÑ? СоздаÑÑ Ð½ÐµÐ·Ð°Ð²Ð¸ÑимÑÑ ÐºÐ¾Ð¿Ð¸Ñ, клон?
ÐÑо Ñоже вÑполнимо, но немного Ñложнее, поÑÐ¾Ð¼Ñ ÑÑо в JavaScript Ð´Ð»Ñ ÑÑого Ð½ÐµÑ Ð²ÑÑÑоенного меÑода. Ðо на Ñамом деле в ÑÑом Ñедко Ð²Ð¾Ð·Ð½Ð¸ÐºÐ°ÐµÑ Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ÑÑÑ, копиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾ ÑÑÑлке в болÑÑинÑÑве ÑлÑÑаев вполне Ñ Ð²Ð°ÑаеÑ.
Ðо еÑли Ð¼Ñ Ð´ÐµÐ¹ÑÑвиÑелÑно ÑÑого Ñ Ð¾Ñим, Ñо нам нÑжно ÑоздаÑÑ Ð½Ð¾Ð²Ñй обÑÐµÐºÑ Ð¸ воÑпÑоизвеÑÑи ÑÑÑÑкÑÑÑÑ ÑÑÑеÑÑвÑÑÑего, пеÑебÑав его ÑвойÑÑва и ÑкопиÑовав Ð¸Ñ Ð½Ð° пÑимиÑивном ÑÑовне.
ÐапÑÐ¸Ð¼ÐµÑ Ñак:
let user = {
name: "John",
age: 30
};
let clone = {}; // новÑй пÑÑÑой обÑекÑ
// давайÑе ÑкопиÑÑем вÑе ÑвойÑÑва user в него
for (let key in user) {
clone[key] = user[key];
}
// ÑепеÑÑ clone ÑÑо полноÑÑÑÑ Ð½ÐµÐ·Ð°Ð²Ð¸ÑимÑй обÑÐµÐºÑ Ñ Ñем же ÑодеÑжимÑм
clone.name = "Pete"; // изменим в нÑм даннÑе
alert( user.name ); // вÑе еÑÑ John в пеÑвонаÑалÑном обÑекÑе
Также Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ иÑполÑзоваÑÑ Ð´Ð»Ñ ÑÑого меÑод Object.assign.
СинÑакÑиÑ:
Object.assign(dest, [src1, src2, src3...])
- ÐеÑвÑй аÑгÑменÑ
destâ Ñелевой обÑекÑ. - ÐÑÑалÑнÑе аÑгÑменÑÑ
src1, ..., srcN(Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÑÑолÑко, ÑколÑко Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾) ÑвлÑÑÑÑÑ Ð¸ÑÑ Ð¾Ð´Ð½Ñми обÑекÑами - ÐеÑод копиÑÑÐµÑ ÑвойÑÑва вÑеÑ
иÑÑ
однÑÑ
обÑекÑов
src1, ..., srcNв Ñелевой обÑекÑdest. ÐÑÑгими Ñловами, ÑвойÑÑва вÑÐµÑ Ð°ÑгÑменÑов, наÑÐ¸Ð½Ð°Ñ Ñо вÑоÑого, копиÑÑÑÑÑÑ Ð² пеÑвÑй обÑекÑ. - ÐозвÑаÑÐ°ÐµÑ Ð¾Ð±ÑекÑ
dest.
ÐапÑимеÑ, Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ иÑполÑзоваÑÑ ÐµÐ³Ð¾ Ð´Ð»Ñ Ð¾Ð±ÑÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ð½ÐµÑколÑÐºÐ¸Ñ Ð¾Ð±ÑекÑов в один:
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// копиÑÑем вÑе ÑвойÑÑва из permissions1 и permissions2 в user
Object.assign(user, permissions1, permissions2);
// ÑепеÑÑ user = { name: "John", canView: true, canEdit: true }
ÐÑли ÑкопиÑованное Ð¸Ð¼Ñ ÑвойÑÑва Ñже ÑÑÑеÑÑвÑеÑ, оно бÑÐ´ÐµÑ Ð¿ÐµÑезапиÑано:
let user = { name: "John" };
Object.assign(user, { name: "Pete" });
alert(user.name); // ÑепеÑÑ user = { name: "Pete" }
ÐÑ Ñакже можем иÑполÑзоваÑÑ Object.assign Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÐ½Ñ Ñикла for..in Ð´Ð»Ñ Ð¿ÑоÑÑого клониÑованиÑ:
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
Ðн копиÑÑÐµÑ Ð²Ñе ÑвойÑÑва user в пÑÑÑой обÑÐµÐºÑ Ð¸ возвÑаÑÐ°ÐµÑ ÐµÐ³Ð¾.
Также ÑÑÑеÑÑвÑÑÑ Ð¸ дÑÑгие меÑÐ¾Ð´Ñ ÐºÐ»Ð¾Ð½Ð¸ÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±ÑекÑа. ÐапÑимеÑ, Ñ Ð¸ÑполÑзованием опеÑаÑоÑа ÑаÑÑиÑÐµÐ½Ð¸Ñ clone = {...user}, ÑаÑÑмоÑÑенного далее в ÑÑебнике.
Ðложенное клониÑование
Ðо ÑиÑ
Ð¿Ð¾Ñ Ð¼Ñ Ð¿Ñедполагали, ÑÑо вÑе ÑвойÑÑва user пÑимиÑивнÑe. Ðо ÑвойÑÑва могÑÑ Ð±ÑÑÑ Ð¸ ÑÑÑлками на дÑÑгие обÑекÑÑ. ЧÑо Ñ Ð½Ð¸Ð¼Ð¸ делаÑÑ?
ÐапÑимеÑ, еÑÑÑ Ð¾Ð±ÑекÑ:
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
alert( user.sizes.height ); // 182
ТепеÑÑ Ð½ÐµÐ´Ð¾ÑÑаÑоÑно пÑоÑÑо ÑкопиÑоваÑÑ clone.sizes = user.sizes, поÑÐ¾Ð¼Ñ ÑÑо user.sizes â ÑÑо обÑекÑ, он бÑÐ´ÐµÑ ÑкопиÑован по ÑÑÑлке. Таким обÑазом, clone и user бÑдÑÑ Ð¸Ð¼ÐµÑÑ Ð¾Ð±Ñий обÑÐµÐºÑ sizes:
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, ÑÐ¾Ñ Ð¶Ðµ обÑекÑ
// user и clone обладаÑÑ Ð¾Ð±Ñим ÑвойÑÑвом sizes
user.sizes.width++; // изменÑем ÑвойÑÑва в пеÑвом обÑекÑе
alert(clone.sizes.width); // 51, видим ÑезÑлÑÑÐ°Ñ Ð² дÑÑгом
ЧÑÐ¾Ð±Ñ Ð¸ÑпÑавиÑÑ ÑÑо, Ð¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¸ÑполÑзоваÑÑ Ñикл клониÑованиÑ, коÑоÑÑй пÑовеÑÑÐµÑ ÐºÐ°Ð¶Ð´Ð¾Ðµ знаÑение user[key] и, еÑли ÑÑо обÑекÑ, Ñогда Ñакже копиÑÑÐµÑ ÐµÐ³Ð¾ ÑÑÑÑкÑÑÑÑ. ÐÑо назÑваеÑÑÑ Â«Ð³Ð»Ñбоким клониÑованием».
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ ÑеализоваÑÑ Ð³Ð»Ñбокое клониÑование, иÑполÑзÑÑ ÑекÑÑÑиÑ. Ðли, ÑÑÐ¾Ð±Ñ Ð½Ðµ изобÑеÑаÑÑ Ð²ÐµÐ»Ð¾Ñипед заново, возÑмиÑе гоÑовÑÑ ÑеализаÑиÑ, напÑÐ¸Ð¼ÐµÑ _.cloneDeep(obj) из библиоÑеки JavaScript lodash.
Также Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ иÑполÑзоваÑÑ Ð³Ð»Ð¾Ð±Ð°Ð»ÑнÑй меÑод structuredClone(), коÑоÑÑй позволÑÐµÑ ÑделаÑÑ Ð¿Ð¾Ð»Ð½ÑÑ ÐºÐ¾Ð¿Ð¸Ñ Ð¾Ð±ÑекÑа. Ð ÑÐ¾Ð¶Ð°Ð»ÐµÐ½Ð¸Ñ Ð¾Ð½ поддеÑживаеÑÑÑ ÑолÑко ÑовÑеменнÑми бÑаÑзеÑами. ÐдеÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ ознакомиÑÑÑÑ Ñ Ð¿Ð¾Ð´Ð´ÐµÑжкой ÑÑого меÑода.
ÐажнÑм побоÑнÑм ÑÑÑекÑом Ñ
ÑÐ°Ð½ÐµÐ½Ð¸Ñ Ð¾Ð±ÑекÑов в каÑеÑÑве ÑÑÑлок ÑвлÑеÑÑÑ Ñо, ÑÑо обÑекÑ, обÑÑвленнÑй как const, Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¸Ð·Ð¼ÐµÐ½Ñн.
ÐапÑимеÑ:
const user = {
name: "John"
};
user.name = "Pete"; // (*)
alert(user.name); // Pete
ÐÐ¾Ð¶ÐµÑ Ð¿Ð¾ÐºÐ°Ð·Ð°ÑÑÑÑ, ÑÑо ÑÑÑока (*) вÑÐ·Ð¾Ð²ÐµÑ Ð¾ÑибкÑ, но, ÑÑо не Ñак. ÐнаÑение user ÑÑо конÑÑанÑа, оно вÑегда должно ÑÑÑлаÑÑÑÑ Ð½Ð° один и ÑÐ¾Ñ Ð¶Ðµ обÑекÑ, но ÑвойÑÑва ÑÑого обÑекÑа могÑÑ Ñвободно изменÑÑÑÑÑ.
ÐÑÑгими Ñловами, const user вÑдаÑÑ Ð¾ÑÐ¸Ð±ÐºÑ ÑолÑко в Ñом ÑлÑÑае, еÑли Ð¼Ñ Ð¿Ð¾Ð¿ÑÑаемÑÑ Ð·Ð°Ð´Ð°ÑÑ user=... в Ñелом.
Тем не менее, еÑли нам дейÑÑвиÑелÑно нÑжно ÑоздаÑÑ Ð¿Ð¾ÑÑоÑннÑе ÑвойÑÑва обÑекÑа, ÑÑо Ñоже возможно, но Ñ Ð¸ÑполÑзованием ÑовеÑÑенно дÑÑÐ³Ð¸Ñ Ð¼ÐµÑодов. ÐÑ Ð·Ð°ÑÑонем ÑÑо в главе Флаги и деÑкÑипÑоÑÑ ÑвойÑÑв.
ÐÑого
ÐбÑекÑÑ Ð¿ÑиÑваиваÑÑÑÑ Ð¸ копиÑÑÑÑÑÑ Ð¿Ð¾ ÑÑÑлке. ÐÑÑгими Ñловами, пеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ Ñ ÑÐ°Ð½Ð¸Ñ Ð½Ðµ «знаÑение обÑекÑа», а «ÑÑÑлкÑ» (адÑÐµÑ Ð² памÑÑи) на ÑÑо знаÑение. Таким обÑазом, копиÑование Ñакой пеÑеменной или пеÑедаÑа ÐµÑ Ð² каÑеÑÑве аÑгÑменÑа ÑÑнкÑии копиÑÑÐµÑ ÑÑÑ ÑÑÑлкÑ, а не Ñам обÑекÑ.
ÐÑе опеÑаÑии Ñ Ð¸ÑполÑзованием ÑкопиÑованнÑÑ ÑÑÑлок (напÑимеÑ, добавление/Ñдаление ÑвойÑÑв) вÑполнÑÑÑÑÑ Ñ Ð¾Ð´Ð½Ð¸Ð¼ и Ñем же обÑекÑом.
ЧÑÐ¾Ð±Ñ ÑоздаÑÑ Â«ÑеалÑнÑÑ ÐºÐ¾Ð¿Ð¸Ñ» (клон), Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ иÑполÑзоваÑÑ Object.assign Ð´Ð»Ñ Ñак назÑваемой «повеÑÑ
ноÑÑной копии» (вложеннÑе обÑекÑÑ ÐºÐ¾Ð¿Ð¸ÑÑÑÑÑÑ Ð¿Ð¾ ÑÑÑлке) или ÑÑнкÑÐ¸Ñ Â«Ð³Ð»Ñбокого клониÑованиÑ», ÑакÑÑ ÐºÐ°Ðº _.cloneDeep(obj).
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)