использовать элементы массива в качестве координат для доступа к объекту - PullRequest
0 голосов
/ 07 августа 2020

Я пытаюсь реализовать функцию, которая использует элементы массива для доступа к определенным c свойствам объекта в такой ситуации:

let foo = {
    bar:{
        baz:"oldVal",
    }
}

let coodinates = ["bar", "baz"]

function accessAndModify(obj, coord, newVal){
    //should do this: obj[coord[0]][coord[1]]...[coord[coord.length - 1]] = newVal;
}

Я пробовал следующее:

function accessAndModify(obj, coord, ewVal) {
    try {
        [obj, ...coord].reduce((x, y) => x[y]) = newVal;
    } catch (e) {
        return false;
    }
}

, но возникла следующая ошибка: ReferenceError: неверная левая часть в назначении.

Ответы [ 4 ]

1 голос
/ 07 августа 2020

Проблема с вашим кодом заключается в том, что вы заходите слишком далеко вниз по иерархии объектов, и ваше сокращение возвращает значение obj['bar']['baz'], когда вы действительно хотите obj['bar'], чтобы затем вы могли установить элемент baz этого возражать против нового значения. Если вы остановите сокращение на один элемент раньше, ваш код заработает:

let foo = {
  bar: {
    baz: "oldVal",
  }
}

let coordinates = ["bar", "baz"]

function accessAndModify(obj, coord, newVal) {
  try {
    [obj, ...coord.slice(0, -1)].reduce((x, y) => x[y])[coord[coord.length - 1]] = newVal;
  } catch (e) {
    return false;
  }
}

console.log(foo);
accessAndModify(foo, coordinates, 'newVal');
console.log(foo);
0 голосов
/ 07 августа 2020

Вам нужно будет продолжать получать следующее свойство глубоко в obj, но как только вы окажетесь на последнем, вам нужно будет установить его, прежде чем возвращать его, чтобы вы изменяли свойство объекта, а не примитив. Сделать это можно так:

let foo = {
    bar:{
        baz:"oldVal",
    }
}

let coordinates = ["bar", "baz"]

function accessAndModify(obj, coord, newVal) {
    try {
        coord.reduce((carry, current, index) => {
            if (index === coord.length - 1) {
                carry[current] = newVal;
            }
            return carry[current];
        }, obj);
    } catch (e) {
        return false;
    }
}

accessAndModify(foo, coordinates, 'newVal');
console.log(foo);
0 голосов
/ 07 августа 2020

Reduce принимает начальное начальное значение в качестве второго аргумента после функции обратного вызова, поэтому вам не нужно создавать новый массив с начальным объектом, вместо этого установите начальное значение для объекта.

Затем, прежде чем использовать сокращение coord, удалите последний элемент из координаты (используя .pop()) и поместите его в переменную с именем last, таким образом вы получите последний объект, чтобы вы могли обновить его значение, если если вы не извлекли значение, то reduce вернет строковое значение, которое вы пытаетесь обновить, а не ссылку на объект.

См. пример ниже:

let foo = {
  bar: {
    baz: "oldVal",
  }
}

let coordinates = ["bar", "baz"];

function accessAndModify(obj, coord, newVal) {
  try {
    const last = coord.pop(); // coord changes and last is assigned last value in array
    const foundObj = coord.reduce((x, y) => x[y], obj);
    foundObj[last] = newVal;
  } catch (e) {
    return false;
  }
}

accessAndModify(foo, coordinates, "newVal");
console.log(foo);
0 голосов
/ 07 августа 2020

Вам нужно назначить результат reduce() объекту и вернуть res.

function accessAndModify(obj, coord, newVal) {
    try {
        const res = [obj, ...coord].reduce((x, y) => x[y]) = newVal;
        return res;
    } catch (e) {
        return false;
    }
}

или вернуть результат из reduce() напрямую.

function accessAndModify(obj, coord, newVal) {
    try {
        return [obj, ...coord].reduce((x, y) => x[y]) = newVal;
    } catch (e) {
        return false;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...