Мысли из вопроса интервью

внешний интерфейс JavaScript регулярное выражение опрос

Сегодня, когда я серьезно занимался (забастовкой) работой (водой), я увидел, что кто-то в группе разместил заголовок интервью. Я посмотрел на него и нашел его очень интересным, поэтому я решил поделиться им с вами и поделиться своим мнением. решение Сценарии и мыслительный процесс.

Темы следующие:

Реализуйте функцию get, чтобы следующий вызов выдавал правильный результат.

const obj = { selector: { to: { toutiao: "FE Coder"} }, target: [1, 2, { name: 'byted'}]};

get(obj, 'selector.to.toutiao', 'target[0]', 'target[2].name');
// [ 'FE Coder', 1, 'byted']

На первый взгляд, разве это не просто реализация метода lodash.get? Это кажется достаточно простым. Так я начал писать первую версию. Идея на самом деле очень проста: пройтись по входящим параметрам, использовать split для разделения каждого параметра, затем пройтись по значениям и, наконец, вернуть результат.

function get(data, ...args) {
	return args.map((item) => {
		const paths = item.split('.');
		let res = data;
		paths.map(path => res = res[path]);
		return res;
	})
}

Как только он запускается, как и ожидалось, сообщается об ошибке.

Позже я внимательно посмотрел предоставленный тестовый код и обнаружил, что есть такая вещь, как target[0]. . Даже с индексом массива.

Спокойно проанализируйте, для типа с индексом позади, таким как 'target[0]', мы должны относиться к нему по-особому. Итак, мы должны сначала распознать этот специальный тип, а затем провести над ним дополнительную обработку.

В настоящее время вы можете быстро подумать об использовании регулярных выражений для этого. Зачем? Поскольку у этих типов с индексами есть характеристика, то есть они имеют фиксированный формат: [число], то для решения этой проблемы нам нужно только иметь возможность построить регулярку, которая может соответствовать этому фиксированному формату.

Для этого формата нетрудно подумать, что это регулярное выражение может быть использовано для оценки: /\[[0-9]+\]/gi, но нам также нужно вынуть соответствующее значение. В это время я проверил документацию по регулярным выражениям (Документация нажмите здесь) и обнаружил, что существует метод match, который может вернуть результат успешного совпадения. Итак, давайте проведем тест:

const reg = /\[[0-9]+\]/gi;
const str = "target[123123]";
const str1 = "target[]"

if (reg.test(str)) {
    console.log('test success');
}

if (!reg.test(str1)) {
    console.log('test fail');
}

const matchResult = str.match(reg);
console.log(matchResult); // ["[123123]"]

Привет, теперь мы нашли решение этой проблемы, так что давайте поторопимся и продолжим улучшать код.

function get(data, ...args) {
	const reg = /\[[0-9]+\]/gi;
	return args.map((item) => {
		const paths = item.split('.');
		let res = data;
		paths.map((path) => {
                  if (reg.test(path)) {
                    const match = path.match(reg)[0];
                    // 将target[0]里的target储存到cmd里
                    const cmd = path.replace(match, '');
                    // 获取数组索引
                    const arrIndex = match.replace(/[\[\]]/gi, '');
                    res = res[cmd][arrIndex];
                  } else {
                    res = res[path];
                  }
		});
		return res;
	});
}


const obj = { selector: { to: { toutiao: "FE Coder"} }, target: [1, 2, { name: 'byted'}]};

console.log(get(obj, 'selector.to.toutiao', 'target[0]', 'target[2].name'));

Написав его, запустите его быстро, он идеален, и выводится правильный результат. Так это заканчивается здесь?

Улучшать

Но я всегда чувствую, что что-то не так, что все не так просто. Вообще говоря, в дополнение к проверке вашей способности решать проблемы, вопросы на собеседовании могут также проверить полноту и строгость вашего мышления. Как и в приведенном выше способе написания, если пользователь переходит по несуществующей цепочке путей или при каких-то других особых обстоятельствах, это может привести к сбою всей программы. Подумайте о методе вызова lodash.get, даже если вы перейдете по неправильному пути, он может обработать его за вас и вернуть неопределенное значение. Поэтому нам еще нужно усовершенствовать этот метод.

function get(data, ...args) {
	const reg = /\[[0-9]+\]/gi;
	return args.map((item) => {
		const paths = item.split('.');
		let res = data;
		paths.map(path => {
			try {
				if (reg.test(path)) {
					const match = path.match(reg)[0];
					const cmd = path.replace(match, '');
					const arrIndex = match.replace(/[\[\]]/gi, '');
					res = res[cmd][arrIndex];
				} else {
					res = res[path];
				}
			} catch (err) {
				console.error(err);
				res = undefined;
			}
		});
		return res;
	});
}

Здесь мы пытаемся обработать catch для каждой обработки пути. В случае ошибки вернуть undefined. Вау, это выглядит более стабильно.

Итак, есть ли другое решение?

Большой парень в группе предложил более простое и хитрое решение, заключающееся в том, чтобы решить эту проблему путем создания функции (щелкните, чтобы получить подробное описание функции).здесь). Поскольку код очень простой, я вставлю его напрямую:

function get(data, ...args) {
	const res = JSON.stringify(data);
	return args.map((item) => (new Function(`try {return ${res}.${item} } catch(e) {}`))());
}

const obj = { selector: { to: { toutiao: "FE Coder"} }, target: [1, 2, { name: 'byted'}]};

console.log(get(obj, 'selector.to.toutiao', 'target[0]', 'target[2].name', 'asd'));

После прочтения всего два слова, круто.

Признаюсь, я сначала не ожидал этого метода, он действительно очень умный. Но если хорошенько подумать, на самом деле многие фреймворки используют этот трюк. Например, в Vue новый метод Function используется для динамического создания функций для решения проблемы выполнения динамически сгенерированного кода.

image-20181123104236389

image-20181123104312474

Для другого примера, в методе Function.prototype.bind (я написал аналогичный метод привязки:склад), также использовал функцию для решения некоторых проблем (проблема потери fn.length). Это показывает, что эта штука довольно полезная, ее нужно изучить и понять, может быть, когда-нибудь вы ей воспользуетесь.

возобновить

Кто-то упомянул, что метод Function не может обрабатывать следующую обработку:

let obj = {time : new Date(), a : "this is a", b : 30};

Потому что после JSON.stringify переменные типа Date, Function и RegExp будут недействительны. Для этой ситуации есть большой парень в разделе комментариев (Фэн Хэнчжи) также упомянул хорошее решение:

function get(data, ...args) {
    return args.map((item) => (new Function('data',`try {return data.${item} } catch(e) {}`))(data));
}

Помимо,Код ВселеннаяПредлагается другое решение, которое состоит в том, чтобы разделить «target[0]» на два ключа, что тоже очень просто и грубо, то есть перед разделением заменить '[' в строке на '.', а '] ' Просто удалите его. Это превращает «цель [0]» в «цель.0». Конкретный код выглядит следующим образом:

function get(data, ...args) {
    return args.map((item) => {
				let res = data;
				item
					.replace(/\[/g, ".")
					.replace(/\]/g, "")
					.split('.')
					.map(path => res = res && res[path]);
        return res;
    })
}

Преимущество этих двух методов в том, что они также могут обрабатывать случай многомерных массивов.

Суммировать

После изучения самое главное подвести итоги, только после подведения итогов знания свои. Итак, позвольте мне резюмировать то, что хочет выразить статья:

  1. Для строк с фиксированным форматом рассмотрите возможность использования регулярных выражений для идентификации и сопоставления.
  2. При реализации функции учитывайте не только нормальные ситуации, но и некоторые нештатные ситуации, такие как неверный формат ввода, несоблюдение пользователем процедуры или сообщения об ошибках из-за каких-то странных вещей. И может выполнять отказоустойчивую обработку предсказуемых нештатных ситуаций.
  3. Иногда вы можете узнать больше о некоторых черных технологиях (таких как Функция), и, возможно, однажды вы сможете использовать их для решения проблем.

Адрес этой статьи находится по адресу ->Адрес моего блога, добро пожаловать, чтобы начать или подписаться