Эта статья представляет собой расшифровку моей бесплатной серии YouTube об основах веб-разработки. Если вы предпочитаете смотреть, а не читать, посетите мой канал Dev Newbs.

Привет, мои коллеги новички! Сегодня у нас будет небольшое дежавю. Мы поговорим о методе replaceAll(), который почти идентичен методу replace(). Конечно, за некоторыми исключениями. И вы найдете их в сегодняшнем выпуске.

Метод replaceAll() возвращает новую строку, в которой все совпадения шаблона заменены заменой. Шаблон является первым параметром и может быть либо регулярным выражением, либо простым строковым значением. Замена — это второй параметр, и это может быть либо простое строковое значение, либо функция, вызываемая для каждого совпадения. Если регулярное выражение не содержит глобального флага, выдается TypeError.

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

const str = "The blue sweater itches. I'll wear a red t-shirt and a blue jeans.";
let regExp = /blue/g;
// PATTERN:     string
// REPLACEMENT: string
console.log("S  -> S  : " + str.replaceAll("blue", "green"));
// OUTPUT:
// S  -> S  : The green sweater itches. I'll wear a red t-shirt and // a green jeans.
// PATTERN:     RexExp
// REPLACEMENT: string
console.log("RE -> S  : " + str.replaceAll(regExp, "green"));
// OUTPUT:
// RE -> S  : The green sweater itches. I'll wear a red t-shirt and // a green jeans.
// PATTERN:     string
// REPLACEMENT: function
console.log
(
    "S  -> fn : " +
    str.replaceAll
    (
        "blue", 
        (x) => {
            return x.toUpperCase()
        }
    )
);
// OUTPUT:
// S  -> fn : The BLUE sweater itches. I'll wear a red t-shirt and a // BLUE jeans.
// PATTERN:     RexExp
// REPLACEMENT: function
console.log
(
    "RE -> fn : " +
    str.replaceAll(
        regExp, 
        function (x) 
        {
            return x.toUpperCase()
        }
    )
);
// OUTPUT:
// RE -> fn : The BLUE sweater itches. I'll wear a red t-shirt and a // BLUE jeans.

Здесь снова доступны четыре комбинации типов значений «шаблон» и «замена».

В первом мы ищем строку «синий» и заменяем ее строкой «зеленый». Все найденные вхождения заменены. На данный момент это самое важное различие между двумя методами.

Во втором случае используется регулярное выражение для поиска совпадения, которое нужно заменить простым строковым значением «зеленый». Поскольку мы используем глобальный флаг в нашем регулярном выражении, мы будем заменять все совпадения, а не только первое.

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

Последний — четвертый случай — это совпадение с регулярным выражением, которое заменяется функцией. Мы заменяем строчную версию на прописную.

Если вы забудете добавить глобальный флаг в регулярное выражение, вы получите TypeError.

try {
    let re = /(\w+)\s(\w+)/;
    let fullName = 'John Smith';
    let newstr = fullName.replaceAll(re, '$2, $1');
    console.log(newstr);  // Smith, John
}
catch(err){
    console.log(err);
}
// OUTPUT:
// TypeError: String.prototype.replaceAll called with a non-global // RegExp argument at String.replaceAll (<anonymous>)
try {
    let re = /(\w+)\s(\w+)/g;
    let fullName = 'John Smith';
    let newstr = fullName.replaceAll(re, '$2, $1');
    console.log(newstr);  // Smith, John
}
catch(err){
    console.log(err);
}
// OUTPUT:
// Smith, John

TypeError сообщает нам, что нам нужно предоставить глобальное RegExp. Мы делаем его, добавляя «g» в конце выражения. Простой. И теперь это работает.

Есть несколько приемов, которые вы можете использовать, когда указываете строку в качестве параметра. Вот некоторые из них в примере 3.

let myList = 'John Adam Peter Herb';
// $$ -> inserts "$"
myList.replaceAll("Peter", '$$')          
// OUTPUT:
// John Adam $ Herb
// $& -> inserts "matched substring"
myList.replaceAll("Peter", '$& $& $&') 
// OUTPUT:
// John Adam Peter Peter Peter Herb
// $` -> inserts "the portion of the string that precedes the matched substring"
myList.replaceAll("Peter ", '$`')
// OUTPUT:
// John Adam John Adam Herb
// $' -> inserts "the portion of the string that follows the matched substring"
myList.replaceAll(" Peter", "$'")
// OUTPUT:
// John Adam Herb Herb

Вы можете вывести символ «$», набрав его дважды. Или вы можете вставить совпадающую строку несколько раз вместо замены. Если это то, что вам нужно, «$&» — это то, что вам нужно. Иногда вам нужна подстрока, предшествующая совпавшей строке. В этом случае вы можете использовать «$`», и вот что вы получите. В качестве альтернативы вам может понадобиться подстрока, следующая за совпавшей строкой. В этом случае вы можете использовать «$», и все готово. Я не совсем уверен, что вы можете использовать его каким-либо образом, но, по крайней мере, теперь вы знаете, что можете это сделать. Ура!

В последнем примере показаны некоторые приемы, которые можно использовать при использовании функции в качестве замещающего параметра.

let myBiggerList = 'John Adam Peter Herb Paul Marty';
let rgEx = /(P)([a-z]+)/gi;
myBiggerList.replaceAll
(
    rgEx, 
    function
    (
        match, 
        p1, 
        p2, 
        offset, 
        str
    )
    {
        console.log(match);
        console.log(p1);
        console.log(p2);
        console.log(offset);
        console.log(str);
        console.log("");
    }
);
// OUTPUT:
// Peter
// P
// eter
// 10
// John Adam Peter Herb Paul Marty
// 
// Paul
// P
// aul
// 21
// John Adam Peter Herb Paul Marty

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

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

Как и в предыдущем методе, это было очень весело. Но мы все равно сейчас в конце. Спасибо за ваше неизменное внимание и, как обычно, увидимся в следующий раз.