Строки шаблона для серии ES6

внешний интерфейс GitHub JavaScript регулярное выражение
Строки шаблона для серии ES6

Основное использование

let message = `Hello World`;
console.log(message);

Если вы хотите использовать обратную косую черту в строке, вы можете избежать ее с помощью обратной косой черты:

let message = `Hello \` World`;
console.log(message);

Стоит отметить, что в шаблонных строках сохраняются пробелы, отступы и символы новой строки:

let message = `
	<ul>
		<li>1</li>
		<li>2</li>
	</ul>
`;
console.log(message);

string

Обратите внимание, что первая строка в напечатанном результате является новой строкой, вы можете использовать функцию обрезки, чтобы удалить новую строку:

let message = `
	<ul>
		<li>1</li>
		<li>2</li>
	</ul>
`.trim();
console.log(message);

string

Встроенные переменные

Строки шаблона поддерживают встроенные переменные. Вам нужно только написать имя переменной в ${}. На самом деле возможны не только переменные, но и любое выражение JavaScript:

let x = 1, y = 2;
let message = `<ul><li>${x}</li><li>${x + y}</li></ul>`;
console.log(message); // <ul><li>1</li><li>3</li></ul>

Стоит отметить, что строки шаблона поддерживают вложенность:

let arr = [{value: 1}, {value: 2}];
let message = `
	<ul>
		${arr.map((item) => {
			return `
				<li>${item.value}</li>
			`
		})}
	</ul>
`;
console.log(message);

Результат печати следующий:

string

Обратите внимание, что в середине тега li есть дополнительная запятая, потому что, когда значение в фигурных скобках не является строкой, оно будет преобразовано в строку, например, массив [1, 2, 3] будет преобразован в 1, 2, 3 запятая генерируется так.

Если вы хотите избавиться от запятой, вы можете сначала присоединиться:

let arr = [{value: 1}, {value: 2}];
let message = `
	<ul>
		${arr.map((item) => {
			return `
				<li>${item.value}</li>
			`
		}).join('')}
	</ul>
`;
console.log(message);

Результат печати следующий:

string

Шаблон этикетки

Теги шаблона — очень важная возможность.Строка шаблона может следовать сразу за именем функции, которая будет вызываться для обработки строки шаблона.Например:

let x = 'Hi', y = 'Kevin';
var res = message`${x}, I am ${y}`;
console.log(res);

Мы можем настроить функцию сообщения для обработки возвращаемой строки:

// literals 文字
// 注意在这个例子中 literals 的第一个元素和最后一个元素都是空字符串
function message(literals, value1, value2) {
	console.log(literals); // [ "", ", I am ", "" ]
	console.log(value1); // Hi
	console.log(value2); // Kevin
}

Мы сглаживаем его обратно со следующими параметрами:

function message(literals, ...values) {
	let result = '';

	for (let i = 0; i < values.length; i++) {
		result += literals[i];
		result += values[i];
	}

	result += literals[literals.length - 1];

	return result;
}

Вы также можете написать это:

function message(literals, ...values) {
	let result = literals.reduce((prev, next, i) => {
	    let value = values[i - 1];
	    return prev + value + next;
	});

	return result;
}

Научиться собирать его обратно - очень важная вещь, потому что после различных обработок нам все равно придется собирать его обратно в конце...

oneLine

Поговорив об основах, мы можем рассмотреть некоторые практические требования:

let message = `
	Hi,
	Daisy!
	I am
	Kevin.
`;

Для удобочитаемости или по другим причинам я хочу написать новую строку, но окончательный выходной символ находится в одной строке, для чего требуется помощь тегов шаблона, мы пытаемся написать такую ​​функцию:

// oneLine 第一版
function oneLine(template, ...expressions) {
    let result = template.reduce((prev, next, i) => {
        let expression = expressions[i - 1];
        return prev + expression + next;
    });

    result = result.replace(/(\s+)/g, " ");
    result = result.trim();

    return result;
}

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

Используйте следующим образом:

let message = oneLine `
    Hi,
    Daisy!
    I am
    Kevin.
`;
console.log(message); // Hi, Daisy! I am Kevin.

Но если вы воспользуетесь им снова, то обнаружите проблему: что делать, если между символами несколько пробелов? Например:

let message = oneLine`
  Preserve eg sentences.  Double
  spaces within input lines.
`;

Если вы используете этот метод сопоставления,sentences.а такжеDoubleДва пробела между ними также заменяются одним пробелом.

Мы можем оптимизировать его снова. Эффект, который мы хотим, состоит в том, чтобы заменить несколько пробелов перед каждой строкой одним пробелом. Фактически, он должен соответствовать символу новой строки и нескольким пробелам после символа новой строки, а затем заменить его пробелом, мы Регулярное выражение можно изменить на:

result = result.replace(/(\n\s*)/g, " ");

для правильного сопоставления кода. Окончательный код выглядит следующим образом:

// oneLine 第二版
function oneLine(template, ...expressions) {
    let result = template.reduce((prev, next, i) => {
        let expression = expressions[i - 1];
        return prev + expression + next;
    });

    result = result.replace(/(\n\s*)/g, " ");
    result = result.trim();

    return result;
}

stripIndents

Предположим, что есть такой фрагмент HTML:

let html = `
	<span>1<span>
	<span>2<span>
		<span>3<span>
`;

Чтобы сохранить его читабельным, я бы хотел, чтобы окончательный ввод выглядел так:

<span>1<span>
<span>2<span>
<span>3<span>

На самом деле он сопоставляет пробел перед каждой строкой, а затем заменяет его пустой строкой.

// stripIndents 第一版
function stripIndents(template, ...expressions) {
    let result = template.reduce((prev, next, i) => {
        let expression = expressions[i - 1];
        return prev + expression + next;
    });


    result = result.replace(/\n[^\S\n]*/g, '\n');
    result = result.trim();

    return result;
}

Самая сложная часть, вероятно, это регулярное выражение:

result = result.replace(/\n[^\S\n]*/g, '\n');

\Sозначает соответствие непробельному символу

[^\S\n]указывает на совпадение非空白字符а также换行符Символы, отличные от , на самом деле являются пробелами для удаления новой строки.

\n[^\S\n]*Указывает на соответствие символу новой строки и нескольким символам пробела, которые не содержат символ новой строки после новой строки.

replace(/\n[^\S\n]*/g, '\n')Указывает, что символ новой строки и несколько пустых символов, которые не содержат символ новой строки после символа новой строки, заменяются символом новой строки, что фактически означает, что пустые символы после символа новой строки удаляются.

На самом деле нам не нужно так много писать, мы можем написать и так:

result = result.replace(/^[^\S\n]+/gm, '');

Это кажется немного проще. Причина, по которой это может быть написано, заключается в шаблоне сопоставления. Вы обнаружите, что в дополнение к сопоставлению глобального, на этот раз мы также сопоставляем несколько строк. Флаг m используется для указания многострочного входная строка должна рассматриваться как несколько строк, и если используется флаг m, символы ^ и $ соответствуют началу или концу каждой строки во входной строке, а не началу или концу всей строки.

[^\S\n] означает соответствие пробельным символам и удаление новых строк

^[^\S\n]+ означает совпадение с去除换行符的空白字符один или несколько символов, начинающихся с

result.replace(/^[^\S\n]+/gm, '') означает начинать каждую строку с одного или нескольких去除换行符的空白字符Замена его пустой строкой также достигает той же цели.

Окончательный код выглядит следующим образом:

// stripIndents 第二版
function stripIndents(template, ...expressions) {
    let result = template.reduce((prev, next, i) => {
        let expression = expressions[i - 1];
        return prev + expression + next;
    });


    result = result.replace(/^[^\S\n]+/gm, '');
    result = result.trim();

    return result;
}

stripIndent

Обратите внимание, что на этот раз stripIndent на одну букву меньше, чем заголовок предыдущего раздела, и функция, которую мы хотим получить, такова:

let html = `
	<ul>
		<li>1</li>
		<li>2</li>
		<li>3</li>
	<ul>
`;

string

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

Эта реализация немного более громоздка, потому что нам нужно выяснить, сколько пробельных символов нужно удалить в строке.

Идея реализации заключается в следующем:

  1. Используйте функцию match, чтобы сопоставить символы пробела в каждой строке и получить массив, содержащий символы пробела в каждой строке.
  2. Сравнение обхода массива для получения минимальной длины пустых символов
  3. Создайте регулярное выражение и замените каждую строку пробелами минимальной длины.

Реализованный код выглядит следующим образом:

let html = `
	<ul>
		<li>1</li>
		<li>2</li>
		<li>3</li>
	<ul>
`;


function stripIndent(template, ...expressions) {
    let result = template.reduce((prev, next, i) => {
        let expression = expressions[i - 1];
        return prev + expression + next;
    });

    const match = result.match(/^[^\S\n]*(?=\S)/gm);
    console.log(match); // Array [ "    ", "        ", "        ", "        ", "    " ]

    const indent = match && Math.min(...match.map(el => el.length));
    console.log(indent); // 4

    if (indent) {
        const regexp = new RegExp(`^.{${indent}}`, 'gm');
        console.log(regexp); // /^.{4}/gm

        result =  result.replace(regexp, '');
    }

    result = result.trim();

    return result;
}

Стоит отметить, что мы обычно думаем, что обычный.Указывает на соответствие любому символу, фактически соответствует любому отдельному символу, кроме новой строки.

Окончательный упрощенный код выглядит следующим образом:

function stripIndent(template, ...expressions) {
    let result = template.reduce((prev, next, i) => {
        let expression = expressions[i - 1];
        return prev + expression + next;
    });

    const match = result.match(/^[^\S\n]*(?=\S)/gm);
    const indent = match && Math.min(...match.map(el => el.length));

    if (indent) {
        const regexp = new RegExp(`^.{${indent}}`, 'gm');
        result =  result.replace(regexp, '');
    }

    result = result.trim();

    return result;
}

includeArrays

Ранее мы упоминали, что для того, чтобы избежать возврата массива в выражении ${}, автоматическое преобразование приведет к проблеме с несколькими запятыми. Нам нужно каждый раз присоединять ('') к массиву в конце, и посмотрите на пример опять таки:

let arr = [{value: 1}, {value: 2}];
let message = `
	<ul>
		${arr.map((item) => {
			return `
				<li>${item.value}</li>
			`
		}).join('')}
	</ul>
`;
console.log(message);

Используя шаблоны тегов, мы можем легко решить эту проблему:

function includeArrays(template, ...expressions) {
    let result = template.reduce((prev, next, i) => {

        let expression = expressions[i - 1];

        if (Array.isArray(expression)) {
            expression = expression.join('');
        }

        return prev + expression + next;
    });

    result = result.trim();

    return result;
}

наконец

Вы обнаружите, что указанные выше функции повторяются, мы можем упаковать их вместе, реализовать невозможные функции в соответствии с различными конфигурациями. Если вы хотите использовать эти функции в своем проекте, вы можете упаковать их или использовать напрямую.common-tags.

серия ES6

Адрес каталога серии ES6: https://github.com/mqyqingfeng/Blog.

Ожидается, что в серии ES6 будет написано около 20 статей, направленных на углубление понимания некоторых точек знаний ES6, с акцентом на область действия на уровне блоков, шаблоны меток, функции стрелок, реализацию моделирования символов, наборов, карт и обещаний, схему загрузки модулей, асинхронность. обработка и т.п. содержание.

Если есть какие-либо ошибки или неточности, пожалуйста, поправьте меня, большое спасибо. Если вам нравится или у вас есть вдохновение, добро пожаловать в звезду, что также является поощрением для автора.