تغییر ناخواسته مقادیر array در javascript

درود دوستان مشکل عجیبی که در جاوااسکریپت برخوردم اینه که من یک global array دارم و به یک تابعی ارسال میکنم و داخل اون تابع من انتظار دارم که هر بلایی سر اون آرایه بیارم داخل تابع بمونه و در آرایه اصلی هیچ تغییری صورت نگیره واقعا دلیل این کار قابل درک نیست برام

let a = []

function printA(item) {
    console.log(item)
}

function changeA(arr) {
    let newArr = arr
    newArr.push('abc')
}

changeA(a)
printA(a)
2 پسندیده

بخاطر اینکه شما داری یک کپی می گیری با تمام خاصیت ها و اینکه بندازیش تو یک متغیر دیگه مثل زبان های دیگه js کار نمی کنه باید زحمت بکشی ازش با spread اوپرتور یک کپی بگیری

مثلا

let newArry = [...ar]

می تونی آرایه رو یک بار جی سان استرینگفای کنی بندازی داخل یک متغیر

روش دیگه هم مثلا برای آبجکت ها

const copy = array.map(object => ({ ...object }))

شما اگر اون رو بندازی داخل یک متغیر داری ریفرنسشم کپی می کنی بخاطر همین اون newArray تغییر کنه آرایه اصلی a هم تغییر می کنه

این مورد روی آرایه و همینطور آبجکت یک سانه

3 پسندیده

@shahryarjb جان نمیشه از assign استفاده کرد؟

let a = [1,2,3]
let b = Object.assign([], a)

cc @husen

2 پسندیده

درود توماج جان سال نو مبارک. :smiling_face_with_three_hearts: باعث افتخار هستم اساتید و دوستان رو اینجا می بینیم

فکر کنم اونجوری که داخل mdn نوشته assign نمی یاد deep clone بکنه و پراپرتی هارو هم می یاره و ریفرنس رو کپی می کنه

For deep cloning, we need to use alternatives, because Object.assign() copies property values.
If the source value is a reference to an object, it only copies the reference value.

تابع زیر هم هست که مخصوص اینکار هست ولی من برای لیست استفاده نکردمش

که چندین لایه تو در تو هم باشه آبجکت بازم کلون رو کامل می گیره کاری که اسپرید اوپروتور داخلش مشکل داره

1 پسندیده

structuredClone(obj) و JSON.parse(JSON.stringify(obj)) خوب deep clone میکنن

و الان چون حس ناامنی بهم میده قصد دارم در کل پروژه هرچی تابع و متد دارم اولش با یکی از روش ها همه وروردی ها رو deep clone کنم و بنوعی default همه توابع باشه. ولی مثل اینکه مردم با این مورد مشکلی ندارن چون سورس کدهایی که دیدم از این مورد ها اصلا استفاده نکردن برای امینت کدهاشون.

آپدیت:
با Object.freeze هم میشه یک immutable array ساخت: (البته برای deep کردن قضیه باید از forEach و شرط استفاده کرد :frowning: )

let a = deepClone([])

function printA(item) {
    console.log(item)
}

function changeA(arr) {
    let newArr = [...arr]
    return newArr.push('abc')
}

changeA(a)
printA(a)

function deepClone(obj) {
    Object.values(obj).forEach((value) => {
        if (value && typeof value === 'object') {
            deepClone(value)
        }
    })

    return Object.freeze(obj)
}
2 پسندیده