JavaScript에서 문자열 보간을 어떻게 수행 할 수 있습니까?


535

이 코드를 고려하십시오.

var age = 3;

console.log("I'm " + age + " years old!");

문자열 연결을 제외하고 변수 값을 문자열에 삽입하는 다른 방법이 있습니까?


7
: 당신은 커피 스크립트 체크 아웃 할 수 coffeescript.org을
dennismonsewicz

1
다른 사람들이 지적했듯이, 당신이 사용하고있는 방법 입니다 그것에 대해 이동하는 가장 쉬운 방법은. 문자열 내 변수를 참조하고 싶지만 자바 스크립트에서는 연결 (또는 다른 찾기 / 바꾸기 방법)을 사용해야합니다. 당신과 같은 사람들과 나는 아마도 우리 자신의 이익을 위해 PHP에 조금 붙어있을 것입니다.
Lev

4
Underscore.js 템플릿
Jahan

2
연결이 보간이 아니고 사용자가 보간 방법을 물었습니다. Lev가 마침내 답을 제공했다고 생각합니다. 나는 이것이 진짜 질문이 아닌 이유를 이해하지 못한다.
gitb

4
내가 대답 할 수 있다면, 이제 새로운 통역사 (2015 FF 및 Chrome이 이미 지원)를 시작하는 솔루션이 있습니다 : developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… . 예 : Show GRAPH of : ${fundCode}-${funcCode} 나를 얻는다 Show GRAPH of : AIP001-_sma (문자열 1 주위에 백틱을 사용하십시오 .... 여기에 표시되지 않는 것 같습니다)
Marcos

답변:


536

ES6부터 템플릿 리터럴을 사용할 수 있습니다 .

const age = 3
console.log(`I'm ${age} years old!`)

PS 백틱 사용에 유의하십시오 ``.


3
왜 그들이 이것에 대해 백틱과 함께 갔는지 궁금합니다. "$ {age}"가 보간을하기에 충분하지 않습니까?
웃음 레모네이드

5
@LaughingLemonade 이전 버전과의 호환성. 그렇게 구현하면 해당 형식으로 문자열을 인쇄하는 모든 기존 코드가 실패합니다.
thefourtheye

1
@Jonathan 나는 항상 의미있는 캐릭터로 백틱을 싫어합니다. 그러나 이유가 보편적인지 또는 언어 키보드 레이아웃에만 적용되는지 확실하지 않습니다. Backtick은 다음 문자까지 쓸 때까지 기다리는 특수 문자 유형으로, 쓰기를 위해 두 번 누르십시오 (이 시점에서 두 문자를 씁니다). "e"와 같은 일부 문자가 상호 작용하기 때문입니다. 그들과 함께 "ello"를 쓰려고하면 èllo ''가 표시됩니다. 또한 '와는 달리 유형으로 전환해야하기 때문에 다소 성가신 위치에 있습니다 (shift + forwardtick, 또 다른 특수한 예견 문자입니다).
felix

@ felix 그것은 키보드 레이아웃과 관련이 있다고 생각합니다. 당신이 설명하는 것을 "죽은 열쇠"라고합니다. 그것들은 노르웨이 키보드 레이아웃 (내 출신)에도 있으며, 이것은 모든 프로그래밍을 위해 미국 키보드 레이아웃으로 전환하는 이유 중 일부입니다. (미국 키보드에서도 훨씬 쉬운 다른 문자 (예 : [및])가 있습니다.)
Eivind Eklund

239

tl; dr

해당되는 경우 ECMAScript 2015의 템플릿 문자열 리터럴을 사용하십시오.

설명

ECMAScript 5 사양에 따라 직접 수행 할 수있는 방법은 없지만 ECMAScript 6에는 템플릿을 작성하는 동안 준 리터럴 이라고도하는 템플릿 문자열 이 있습니다 . 다음과 같이 사용하십시오.

> var n = 42;
undefined
> `foo${n}bar`
'foo42bar'

에서 유효한 자바 스크립트 표현식을 사용할 수 있습니다 {}. 예를 들면 다음과 같습니다.

> `foo${{name: 'Google'}.name}bar`
'fooGooglebar'
> `foo${1 + 3}bar`
'foo4bar'

다른 중요한 것은 더 이상 여러 줄 문자열에 대해 걱정할 필요가 없다는 것입니다. 간단히 다음과 같이 쓸 수 있습니다

> `foo
...     bar`
'foo\n    bar'

참고 : 위에 표시된 모든 템플릿 문자열을 평가하기 위해 io.js v2.4.0을 사용했습니다. 최신 Chrome을 사용하여 위에 표시된 예제를 테스트 할 수도 있습니다.

참고 : ES6 사양은 이제 최종 확정 되었지만 모든 주요 브라우저에서 아직 구현되지 않았습니다. Mozilla 개발자 네트워크 페이지
에 따르면 Firefox 34, Chrome 41, Internet Explorer 12 버전부터 기본 지원을 위해 구현됩니다. Opera, Safari 또는 Internet Explorer 사용자 인 경우 지금 궁금합니다. , 이 테스트 베드 는 모든 사람이 지원을받을 때까지 놀 수 있습니다.


3
babeljs 를 사용하면 사용할 수 있으므로 코드베이스에 도입 한 다음 나중에 지원 해야하는 브라우저가 구현하면 변환 단계를 중단 할 수 있습니다.
ivarni

표준 문자열을 템플릿 문자열 리터럴로 변환하는 방법이 있습니까? 예를 들어, 표시 목적으로 값을 보간해야하는 변환 표가 포함 된 json 파일이있는 경우? 첫 번째 해결책은 아마도이 상황에서 잘 작동한다고 생각하지만 일반적으로 새로운 문자열 템플릿 구문을 좋아합니다.
nbering

이것은 여전히 ​​js 문자열 보간에 대한 첫 번째 검색 결과 중 하나이므로 지금 일반 가용성을 반영하도록 업데이트 할 수 있다면 좋을 것입니다. "직접적인 방법은 없습니다"는 아마도 대부분의 브라우저에서 더 이상 사실이 아닙니다.
Felix Dombek

2
청중의 시력이 좋지 않으면`캐릭터가 '과 다릅니다. 이 작업을 수행하는 데 문제가 있으면 따옴표 (예 : 기울어 진 따옴표, 역 따옴표) en.wikipedia.org/wiki/Grave_accent를 사용하십시오 . 그것은 키보드의 왼쪽 상단에 있습니다 :)
Quincy

@Quincy Mac 키보드의 왼쪽 하단-백틱 (back-tick) :)
RB.

192

Douglas Crockford의 Remedial JavaScript 에는 String.prototype.supplant함수가 포함되어 있습니다. 짧고 친숙하며 사용하기 쉽습니다.

String.prototype.supplant = function (o) {
    return this.replace(/{([^{}]*)}/g,
        function (a, b) {
            var r = o[b];
            return typeof r === 'string' || typeof r === 'number' ? r : a;
        }
    );
};

// Usage:
alert("I'm {age} years old!".supplant({ age: 29 }));
alert("The {a} says {n}, {n}, {n}!".supplant({ a: 'cow', n: 'moo' }));

String의 프로토 타입을 변경하지 않으려는 경우 언제든지 독립형으로 적용하거나 다른 네임 스페이스 또는 다른 곳에 배치 할 수 있습니다.


102
참고 : 연결하는 것보다 10 배 느리게 실행됩니다.
cllpse

36
그리고 키 입력과 바이트를 약 3 배 더 많이 가져갑니다.
ma11hew28

8
@roosteronacid-속도 저하에 대한 관점을 줄 수 있습니까? 예를 들어 0.01에서 0.1 초 (중요) 또는 0.000000001에서 0.00000001 초 (무관)?
chris

16
@george : 내 컴퓨터에서 빠른 테스트를 한 결과 "소는 moo, moo, moo!" 전달 된 객체에서 변수를 가져 와서 템플릿 문자열의 상수 부분과 연결하는 사전 컴파일 된 함수에 대해 Crockford의 방법 대 111ns를 사용합니다. Chrome 21입니다.
George

13
또는 다음과 같이 사용하십시오 :"The {0} says {1}, {1}, {1}!".supplant(['cow', 'moo'])
Robert Massa

54

주의 사항 : 자체 구분 기호를 벗어날 수없는 템플릿 시스템은 피하십시오. 예를 들어 supplant()여기에 언급 된 방법을 사용하여 다음을 출력 할 방법이 없습니다 .

"저는 {age} 변수 덕분에 3 살입니다."

간단한 보간은 자체 포함 된 작은 스크립트에 효과적 일 수 있지만 종종 심각한 사용을 제한하는이 디자인 결함이 있습니다. 솔직히 다음과 같은 DOM 템플릿을 선호합니다.

<div> I am <span id="age"></span> years old!</div>

그리고 jQuery 조작을 사용하십시오. $('#age').text(3)

또는 단순히 문자열 연결에 지친 경우 항상 대체 구문이 있습니다.

var age = 3;
var str = ["I'm only", age, "years old"].join(" ");

4
사이드 참고 : Array.join()직접 (보다 느린 +(노드와 오늘 JS를 실행하는 거의 모든 것을 포함 V8을 포함) 브라우저 엔진은 대규모을 최적화하고 찬성 차이의 큰 거래가 있기 때문에, 스타일) 연결 직접 연결은
필라프

1
supplant 메소드를 사용하면 언급 한 문자열을 생성 할 수 있습니다. {token}은 데이터 오브젝트에 멤버가 포함 된 경우에만 바뀝니다. token따라서 멤버가 있는 데이터 오브젝트를 제공하지 않으면 age괜찮습니다.
Chris Fewtrell

1
크리스, 그게 어떻게 해결되는지 모르겠다. 나이 변수와 {age} 문자열을 모두 사용하도록 예제를 쉽게 업데이트 할 수 있습니다. 템플릿 복사 텍스트를 기반으로 변수의 이름을 지정할 수있는 것에 대해 정말로 걱정하고 싶습니까? -또한이 포스트 이후로 나는 데이터 바인딩 라이브러리의 열렬한 팬이되었습니다. RactiveJS와 같은 일부는 가변 범위로 가득 찬 DOM에서 저장합니다. 그리고 콧수염과 달리 페이지의 해당 부분 만 업데이트합니다.
greg.kindel

3
기본 답변은 질문에 HTML 태그가 지정되어 있지 않더라도이 자바 스크립트가 브라우저 환경에서 실행되고 있다고 가정하는 것 같습니다.
canon

2
당신의 "주의 단어" supplant는 보증되지 않습니다 : "I am 3 years old thanks to my {age} variable.".supplant({}));주어진 문자열을 정확하게 반환합니다. age주어진 경우 , 여전히 인쇄 {하고 }사용할 수 있습니다{{age}}
le_m

23

sprintf 라이브러리 (완전한 오픈 소스 JavaScript sprintf 구현)를 사용해보십시오 . 예를 들면 다음과 같습니다.

vsprintf('The first 4 letters of the english alphabet are: %s, %s, %s and %s', ['a', 'b', 'c', 'd']);

vsprintf 는 인수 배열을 가져 와서 형식화 된 문자열을 반환합니다.


22

이 패턴을 아직 제대로 수행하는 방법을 모르고 빠르게 아이디어를 얻고 싶을 때 많은 언어로이 패턴을 사용합니다.

// JavaScript
let stringValue = 'Hello, my name is {name}. You {action} my {relation}.'
    .replace(/{name}/g    ,'Indigo Montoya')
    .replace(/{action}/g  ,'killed')
    .replace(/{relation}/g,'father')
    ;

특별히 효율적이지는 않지만 읽을 수 있습니다. 항상 작동하며 항상 사용 가능합니다.

' VBScript
dim template = "Hello, my name is {name}. You {action} my {relation}."
dim stringvalue = template
stringValue = replace(stringvalue, "{name}"    ,"Luke Skywalker")     
stringValue = replace(stringvalue, "{relation}","Father")     
stringValue = replace(stringvalue, "{action}"  ,"are")

항상

* COBOL
INSPECT stringvalue REPLACING FIRST '{name}'     BY 'Grendel'
INSPECT stringvalue REPLACING FIRST '{relation}' BY 'Mother'
INSPECT stringvalue REPLACING FIRST '{action}'   BY 'did unspeakable things to'



6

문자열 보간을위한 간단한 JavaScript 모듈 인 kiwi를 사용해보십시오 .

넌 할 수있어

Kiwi.compose("I'm % years old!", [age]);

또는

Kiwi.compose("I'm %{age} years old!", {"age" : age});

6

console.log출력에서 보간하려는 경우

console.log("Eruption 1: %s", eruption1);
                         ^^

여기에서 %s"형식 지정자"라고합니다. console.log이러한 종류의 보간 지원 기능이 내장되어 있습니다.


1
이것이 유일한 정답입니다. 질문은 템플릿 문자열이 아닌 보간 에 관한 것 입니다.
sospedra

5

다음은 값을 객체에 제공해야하는 솔루션입니다. 개체를 매개 변수로 제공하지 않으면 전역 변수를 사용하는 것이 기본값입니다. 그러나 매개 변수를 사용하는 것이 더 좋습니다. 훨씬 깨끗합니다.

String.prototype.interpolate = function(props) {
    return this.replace(/\{(\w+)\}/g, function(match, expr) {
        return (props || window)[expr];
    });
};

// Test:

// Using the parameter (advised approach)
document.getElementById("resultA").innerText = "Eruption 1: {eruption1}".interpolate({ eruption1: 112 });

// Using the global scope
var eruption2 = 116;
document.getElementById("resultB").innerText = "Eruption 2: {eruption2}".interpolate();
<div id="resultA"></div><div id="resultB"></div>


3
사용하지 마십시오 eval, eval악입니다!
chris97ong

5
@ chris97ong "true"이지만 최소한 이유 ( "evil"이 도움이되지 않음) 또는 대체 솔루션을 제공하십시오. 거의 항상 사용하는 방법이 eval있지만 때로는 그렇지 않습니다. 예를 들어 OP가 조회 객체를 전달하지 않고 (현재 Groovy 보간법과 같은) 현재 범위를 사용하여 보간하는 방법을 원했다면 확실 eval할 것입니다. 오래된 "평가는 악하다"고 의지하지 마십시오.
Ian

1
eval을 사용하지
말고

2
@hasenj 이것이 내가 "최고의 아이디어가 아닐 수도있다" 고 말하고 다른 방법을 제공 한 이유 이다. 그러나 불행히도 evalscope의 지역 변수에 액세스하는 유일한 방법 입니다. 감정이 상하기 때문에 거부하지 마십시오. BTW, 나는 또한 더 안전하기 때문에 다른 방법을 선호하지만 eval방법은 OP의 질문에 정확하게 대답 하는 방법 이므로 대답에 있습니다.
Lucas Trzesniewski

1
문제 eval는 다른 범위에서 var에 액세스 할 수 없으므로 .interpolate호출이 전역이 아닌 다른 함수 내에 있으면 작동하지 않는다는 것입니다.
georg

2

Greg Kindel의 두 번째 답변을 확장 하여 상용구를 제거하는 함수를 작성할 수 있습니다.

var fmt = {
    join: function() {
        return Array.prototype.slice.call(arguments).join(' ');
    },
    log: function() {
        console.log(this.join(...arguments));
    }
}

용법:

var age = 7;
var years = 5;
var sentence = fmt.join('I am now', age, 'years old!');
fmt.log('In', years, 'years I will be', age + years, 'years old!');

1

나는 당신에게 예를 보여줄 수 있습니다 :

function fullName(first, last) {
  let fullName = first + " " + last;
  return fullName;
}

function fullNameStringInterpolation(first, last) {
  let fullName = `${first} ${last}`;
  return fullName;
}

console.log('Old School: ' + fullName('Carlos', 'Gutierrez'));

console.log('New School: ' + fullNameStringInterpolation('Carlos', 'Gutierrez'));


1

ES6부터 객체 키에서 문자열 보간 SyntaxError: expected property name, got '${'을 수행하려면 다음과 같은 작업을 수행하면

let age = 3
let obj = { `${age}`: 3 }

대신 다음을 수행해야합니다.

let obj = { [`${age}`]: 3 }

1

@Chris Nielsen의 포스트의 ES6 버전을 위해 더 많은 것을 대체하십시오 .

String.prototype.supplant = function (o) {
  return this.replace(/\${([^\${}]*)}/g,
    (a, b) => {
      var r = o[b];
      return typeof r === 'string' || typeof r === 'number' ? r : a;
    }
  );
};

string = "How now ${color} cow? {${greeting}}, ${greeting}, moo says the ${color} cow.";

string.supplant({color: "brown", greeting: "moo"});
=> "How now brown cow? {moo}, moo, moo says the brown cow."

0

이전 브라우저에서 템플릿 구문 사용이 실패합니다. 공용 HTML을 작성하는 경우 중요합니다. 연결을 사용하는 것은 지루하고 읽기가 어렵습니다. 특히 표현식이 많거나 긴 경우 또는 괄호를 사용하여 숫자와 문자열 항목의 혼합을 처리해야하는 경우 (둘 다 + 연산자 사용).

PHP는 매우 간단한 표기법을 사용하여 변수와 일부 표현식을 포함하는 따옴표 붙은 문자열을 확장합니다. $a="the color is $color";

JavaScript에서는 var a=S('the color is ',color);가변 개수의 인수를 사용하여 다음을 지원하는 효율적인 함수를 작성할 수 있습니다 . 이 예제에서는 연결에 비해 이점이 없지만 표현식이 길어지면이 구문이 더 명확해질 수 있습니다. 또는 달러 부호를 사용하여 PHP에서와 같이 JavaScript 함수를 사용하여 표현식의 시작을 알릴 수 있습니다.

반면에, 오래된 브라우저를 위해 템플릿과 같은 문자열 확장을 제공하는 효율적인 해결 방법 함수를 작성하는 것은 어렵지 않습니다. 누군가가 이미 해냈을 것입니다.

마지막으로, sprintf (C, C ++ 및 PHP에서와 같이)는 JavaScript로 작성 될 수 있지만 다른 솔루션보다 약간 덜 효율적이라고 생각합니다.


0

사용자 정의 유연한 보간 :

var sourceElm = document.querySelector('input')

// interpolation callback
const onInterpolate = s => `<mark>${s}</mark>`

// listen to "input" event
sourceElm.addEventListener('input', parseInput) 

// parse on window load
parseInput() 

// input element parser
function parseInput(){
  var html = interpolate(sourceElm.value, undefined, onInterpolate)
  sourceElm.nextElementSibling.innerHTML = html;
}

// the actual interpolation 
function interpolate(str, interpolator = ["{{", "}}"], cb){
  // split by "start" pattern
  return str.split(interpolator[0]).map((s1, i) => {
    // first item can be safely ignored
	  if( i == 0 ) return s1;
    // for each splited part, split again by "end" pattern 
    const s2 = s1.split(interpolator[1]);

    // is there's no "closing" match to this part, rebuild it
    if( s1 == s2[0]) return interpolator[0] + s2[0]
    // if this split's result as multiple items' array, it means the first item is between the patterns
    if( s2.length > 1 ){
        s2[0] = s2[0] 
          ? cb(s2[0]) // replace the array item with whatever
          : interpolator.join('') // nothing was between the interpolation pattern
    }

    return s2.join('') // merge splited array (part2)
  }).join('') // merge everything 
}
input{ 
  padding:5px; 
  width: 100%; 
  box-sizing: border-box;
  margin-bottom: 20px;
}

*{
  font: 14px Arial;
  padding:5px;
}
<input value="Everything between {{}} is {{processed}}" />
<div></div>


0

설명하는 경우 템플릿이 가장 적합 할 수 있지만 반복 가능한 / 배열 형식의 데이터 및 / 또는 인수가 있거나 필요한 경우을 사용할 수 있습니다 String.raw.

String.raw({
  raw: ["I'm ", " years old!"]
}, 3);

데이터를 배열로 사용하면 스프레드 연산자를 사용할 수 있습니다.

const args = [3, 'yesterday'];
String.raw({
  raw: ["I'm ", " years old as of ", ""]
}, ...args);

0

내가 찾던 것을 찾을 수 없었습니다.

Node.js를 사용하는 경우 다음 util과 같이 작동하는 형식 함수가 있는 내장 패키지가 있습니다.

util.format("Hello my name is %s", "Brent");
> Hello my name is Brent

우연히 이것은 이제 console.logNode.js에서도 맛에 내장됩니다.

console.log("This really bad error happened: %s", "ReferenceError");
> This really bad error happened: ReferenceError
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.