Các chuỗi được nối từ mẫu ES6 Vs


84

Tôi có mã sau cho Ecma-Script-6 template literals

let person = {name: 'John Smith'};   
let tpl = `My name is ${person.name}.`;    
let MyVar="My name is "+ person.name+".";

console.log("template literal= "+tpl);  
console.log("my variable = "+MyVar);

Kết quả như sau:

template literal= My name is John Smith.
my variable = My name is John Smith.

đây là trò chơi. Tôi đã cố gắng tìm kiếm sự khác biệt chính xác nhưng không thể tìm thấy nó, Câu hỏi của tôi là sự khác biệt giữa hai câu lệnh này là gì,

  let tpl = `My name is ${person.name}.`;    

  let MyVar = "My name is "+ person.name+".";

Tôi đã có thể lấy chuỗi được MyVarnối person.nameở đây, vậy kịch bản sử dụng mẫu theo nghĩa đen là gì?


8
Đây là đặc điểm chung trong các ngôn ngữ khác, về thời gian! Trông gọn gàng hơn, và nó có nhiều dòng.
elclanrs

5
Không chắc bạn muốn nói gì về "sự khác biệt", như tpl === MyVar? Sự khác biệt duy nhất là cú pháp mà chúng được tạo ra. Lưu ý rằng mẫu, trái ngược với nối chuỗi, cũng cung cấp các chức năng thẻ có thể được sử dụng cho những thứ như thoát tự động.
Bergi

Về cơ bản, bạn hỏi sự khác biệt giữa nội suy chuỗi và nối chuỗi là gì.
Damjan Pavlica

Câu trả lời:


104

Nếu bạn đang sử dụng các ký tự mẫu chỉ với các trình giữ chỗ (ví dụ `Hello ${person.name}`) như trong ví dụ của câu hỏi, thì kết quả sẽ giống như chỉ nối các chuỗi. Về mặt chủ quan, nó trông đẹp hơn và dễ đọc hơn, đặc biệt là đối với chuỗi nhiều dòng hoặc chuỗi chứa cả hai '"vì bạn không phải thoát các ký tự đó nữa.

Khả năng đọc là một tính năng tuyệt vời, nhưng điều thú vị nhất về các mẫu là các chữ mẫu được gắn thẻ :

let person = {name: 'John Smith'}; 
let tag = (strArr, name) => strArr[0] + name.toUpperCase() + strArr[1];  
tag `My name is ${person.name}!` // Output: My name is JOHN SMITH!

Trong dòng thứ ba của ví dụ này, một hàm có tên tagđược gọi. Nội dung của chuỗi mẫu được chia thành nhiều biến mà bạn có thể truy cập trong các đối số của taghàm: phần chữ (trong ví dụ này giá trị của strArr[0]My name isvà giá trị của strArr[1]!) và thay thế ( John Smith). Chữ mẫu sẽ được đánh giá theo bất kỳ taghàm nào trả về.

Các ECMAScript wiki liệt kê một số trường hợp sử dụng có thể, như tự động thoát hoặc mã hóa đầu vào, hoặc nội địa hóa. Bạn có thể tạo một hàm thẻ có tên msgđể tra cứu các phần chữ giống như My name isvà thay thế chúng bằng các bản dịch sang ngôn ngữ hiện tại, ví dụ như sang tiếng Đức:

console.log(msg`My name is ${person.name}.`) // Output: Mein Name ist John Smith.

Giá trị được trả về bởi hàm thẻ thậm chí không cần phải là một chuỗi. Bạn có thể tạo một hàm thẻ có tên $để đánh giá chuỗi và sử dụng nó như một bộ chọn truy vấn để trả về một tập hợp các nút DOM, như trong ví dụ này :

$`a.${className}[href=~'//${domain}/']`

2
Đẹp! Nếu bạn có một mẫu khác theo nghĩa đen ở đó, chẳng hạn như $ {person.message}, nó sẽ được dịch theo?
Rigotti

1
@Rigotti Đó là tùy thuộc vào việc thực hiện msgchức năng. Bạn chắc chắn cũng có thể dịch các giá trị thay thế.
kapex

@Beat Toàn bộ trang ecmascript.org dường như đã ngừng hoạt động. Tôi nghĩ rằng họ đã có kế hoạch từ bỏ wiki của họ, vì vậy tôi đã cập nhật các liên kết với các phiên bản lưu trữ.
kapex

Tôi cố gắng chạy $ a.${className}[href=~'//${domain}/']trong bảng điều khiển chrome (và đặt trước đó className=''domain=''nhưng tôi không nhận được các nút DOM mà là mảng chuỗi: / (trong hasn khác, trong jsfiddle, chúng tôi gặp lỗi trong bảng điều khiển: jsfiddle.net/d1fkta76 "Uncaught ReferenceError : $ không được định nghĩa "- tại sao?
Kamil Kiełczewski.

2
@AniketSuryavanshi Dưới đây là so sánh giữa chuỗi mẫu với hiệu suất nối: stackoverflow.com/a/29083467/897024 Một vài năm trước, các chuỗi mẫu chậm hơn nhưng có vẻ như chúng nhanh hơn một chút so với quá trình nối bây giờ.
kapex,

16

ES6đưa ra một loại chuỗi ký tự mới, sử dụng `dấu tích lùi làm dấu phân cách. Các ký tự này cho phép nhúng các biểu thức nội suy chuỗi cơ bản, sau đó được tự động phân tích cú pháp và đánh giá.

let actor = {name: 'RajiniKanth', age: 68};

let oldWayStr = "<p>My name is " + actor.name + ",</p>\n" +
  "<p>I am " + actor.age + " old</p>\n";

let newWayHtmlStr =
 `<p>My name is ${actor.name},</p>
  <p>I am ${actor.age} old</p>`;

console.log(oldWayStr);
console.log(newWayHtmlStr);

Như bạn có thể thấy, chúng tôi đã sử dụng .. '' xung quanh một loạt các ký tự, được hiểu là một chuỗi ký tự, nhưng bất kỳ biểu thức nào của biểu mẫu ${..}đều được phân tích cú pháp và đánh giá nội tuyến ngay lập tức.

Một lợi ích thực sự tuyệt vời của các ký tự chuỗi nội suy là chúng được phép chia thành nhiều dòng:

var Actor = {"name" : "RajiniKanth"};

var text =
`Now is the time for all good men like ${Actor.name}
to come to the aid of their
country!`;
console.log( text );
// Now is the time for all good men
// to come to the aid of their
// country!

Biểu thức nội suy

Bất kỳ biểu thức hợp lệ nào đều được phép xuất hiện bên trong ${..}trong một chuỗi nội suy lit‐ eral, bao gồm các lệnh gọi hàm, lệnh gọi biểu thức hàm nội tuyến, và thậm chí cả các lệnh khác interpo‐ lated string literals!

function upper(s) {
 return s.toUpperCase();
}
var who = "reader"
var text =
`A very ${upper( "warm" )} welcome
to all of you ${upper( `${who}s` )}!`;
console.log( text );
// A very WARM welcome
// to all of you READERS!

Ở đây, nghĩa đen của chuỗi nội suy $ {who} s`` có một chút tiện lợi hơn cho chúng ta khi kết hợp biến who với "s"chuỗi, trái ngược với who + "s". Ngoài ra, để giữ một ghi chú là một chuỗi nội suy, nghĩa đen chỉ lexically scopedở nơi nó xuất hiện, không dynamically scopedtheo bất kỳ cách nào

function foo(str) {
 var name = "foo";
 console.log( str );
}
function bar() {
 var name = "bar";
 foo( `Hello from ${name}!` );
}
var name = "global";
bar(); // "Hello from bar!"

Sử dụng template literalcho HTML chắc chắn dễ đọc hơn bằng cách giảm bớt sự phiền toái.

Cách cũ đơn giản:

'<div class="' + className + '">' +
  '<p>' + content + '</p>' +
  '<a href="' + link + '">Let\'s go</a>'
'</div>';

Với ES6:

`<div class="${className}">
  <p>${content}</p>
  <a href="${link}">Let's go</a>
</div>`
  • Chuỗi của bạn có thể kéo dài nhiều dòng.
  • Bạn không cần phải thoát khỏi các ký tự trích dẫn.
  • Bạn có thể tránh các nhóm như: '">'
  • Bạn không cần phải sử dụng toán tử dấu cộng.

Chữ viết mẫu được gắn thẻ

Chúng ta cũng có thể gắn thẻ một templatechuỗi, khi một templatechuỗi được gắn thẻ, các literalsthay thế và thay thế được chuyển đến hàm trả về giá trị kết quả.

function myTaggedLiteral(strings) {
  console.log(strings);
}

myTaggedLiteral`test`; //["test"]

function myTaggedLiteral(strings,value,value2) {
  console.log(strings,value, value2);
}
let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// "Neat"
// 5

Chúng ta có thể sử dụng spreadtoán tử ở đây để chuyển nhiều giá trị. Đối số đầu tiên - chúng tôi gọi là chuỗi - là một mảng của tất cả các chuỗi thuần túy (thứ nằm giữa bất kỳ biểu thức nội suy nào).

sau đó chúng tôi tập hợp tất cả các đối số tiếp theo vào một mảng được gọi là giá trị bằng cách sử dụng ... gather/rest operator, mặc dù tất nhiên bạn có thể để chúng dưới dạng các tham số được đặt tên riêng lẻ theo sau tham số chuỗi như chúng tôi đã làm ở trên (value1, value2 etc).

function myTaggedLiteral(strings,...values) {
  console.log(strings);
  console.log(values);    
}

let someText = 'Neat';
myTaggedLiteral`test ${someText} ${2 + 3}`;
// ["test ", " ", ""]
// ["Neat", 5]

Tập argument(s)hợp vào mảng giá trị của chúng tôi là kết quả của các biểu thức nội suy đã được đánh giá được tìm thấy trong chuỗi ký tự. A tagged string literalgiống như một bước xử lý sau khi các nội suy được đánh giá nhưng trước khi giá trị chuỗi cuối cùng được biên dịch, cho phép bạn kiểm soát nhiều hơn việc tạo chuỗi từ ký tự. Hãy xem một ví dụ về việc tạo một re-usable templates.

const Actor = {
  name: "RajiniKanth",
  store: "Landmark"
}

const ActorTemplate = templater`<article>
  <h3>${'name'} is a Actor</h3>
  <p>You can find his movies at ${'store'}.</p>

</article>`;

function templater(strings, ...keys) {
  return function(data) {
  let temp = strings.slice();
  keys.forEach((key, i) => {
  temp[i] = temp[i] + data[key];
  });
  return temp.join('');
  }
};

const myTemplate = ActorTemplate(Actor);
console.log(myTemplate);

Chuỗi thô

các hàm thẻ của chúng tôi nhận được một đối số đầu tiên mà chúng tôi đã gọi strings, đó là một array. Nhưng có một chút dữ liệu bổ sung được bao gồm: các phiên bản thô chưa được xử lý của tất cả các chuỗi. Bạn có thể truy cập các giá trị chuỗi thô đó bằng thuộc .rawtính, như sau:

function showraw(strings, ...values) {
 console.log( strings );
 console.log( strings.raw );
}
showraw`Hello\nWorld`;

Như bạn có thể thấy, rawphiên bản của chuỗi giữ nguyên chuỗi \ n thoát, trong khi phiên bản đã xử lý của chuỗi xử lý nó giống như một dòng mới thực không thoát. ES6đi kèm với một built-in chức năng có thể được sử dụng như là một chuỗi thẻ chữ: String.raw(..). Nó chỉ đơn giản là đi qua các phiên bản thô của strings:

console.log( `Hello\nWorld` );
/* "Hello
World" */

console.log( String.raw`Hello\nWorld` );
// "Hello\nWorld"

4

Nó rõ ràng hơn rất nhiều và như đã nêu trong các nhận xét, là một tính năng phổ biến trong các ngôn ngữ khác. Một điều nữa mà tôi thấy hay là cách ngắt dòng, rất hữu ích khi viết chuỗi.

let person = {name: 'John Smith', age: 24, greeting: 'Cool!' };

let usualHtmlStr = "<p>My name is " + person.name + ",</p>\n" +
                   "<p>I am " + person.age + " old</p>\n" +
                   "<strong>\"" + person.greeting +"\" is what I usually say</strong>";


let newHtmlStr = 
 `<p>My name is ${person.name},</p>
  <p>I am ${person.age} old</p>
  <p>"${person.greeting}" is what I usually say</strong>`;


console.log(usualHtmlStr);
console.log(newHtmlStr);

Tôi không hiểu liệu có sự khác biệt lớn giữa dấu ngắt dòng trong một chuỗi và một chữ hay không. kiểm tra es6fiddle.net/i3vj1ldl này . đen chỉ đặt một không gian thay vì ngắt dòng
Naeem Shaikh

1
Ồ, tôi không nói đó là sự khác biệt lớn. Dấu ngắt dòng chữ chỉ là đường cú pháp. Nó chỉ nhằm mục đích dễ đọc.
Rigotti

nhưng bạn vẫn chỉ ra một sự khác biệt tốt. nhưng trước khi chấp nhận câu trả lời của bạn, tôi sẽ đợi một thời gian nhiều hơn cho một câu trả lời tốt hơn trong đó cho thấy bất kỳ sự khác biệt lớn (nếu có bất kỳ!) :)
Naeem Shaikh

2
@NaeemShaikh Tôi thực sự xin lỗi, nhưng ngắt dòng theo nghĩa đen thực sự có tác dụng. Chỉ cần nhận thấy rằng ES6Fiddle chỉ là một cách tồi tệ để kiểm tra nó. Tôi sẽ chỉnh sửa câu trả lời của mình.
Rigotti

2

Trong khi, câu trả lời của tôi không trực tiếp giải quyết câu hỏi. Tôi nghĩ rằng nó có thể được quan tâm khi chỉ ra một nhược điểm của việc sử dụng các ký tự mẫu có lợi cho phép nối mảng.

Hãy nói rằng tôi có

let patient1 = {firstName: "John", lastName: "Smith"};
let patient2 = {firstName: "Dwayne", lastName: "Johnson", middleName: "'The Rock'"};

Vì vậy, một số bệnh nhân có MiddleName và những người khác thì không.

Nếu tôi muốn một chuỗi đại diện cho tên đầy đủ của một bệnh nhân

let patientName = `${patient1.firstName} ${patient1.middleName} ${patient1.lastName}`;

Sau đó, điều này sẽ trở thành "John undefined Smith"

Tuy nhiên nếu tôi đã

let patientName = [patient1.firstName, patient1.middleName,  patient1.lastName].join(" ");

Sau đó, điều này sẽ chỉ trở thành "John Smith"

BIÊN TẬP

General_Twyckenham đã chỉ ra rằng một phép nối trên "" sẽ dẫn đến một khoảng trống thừa giữa "John" và "Smith".

Để giải quyết vấn đề này, bạn có thể có một bộ lọc trước khi tham gia để loại bỏ các giá trị sai: [patient1.firstName, patient1.middleName, patient1.lastName].filter(el => el).join(" ");


2
Trên thực tế, điều đó không hoàn toàn chính xác - joinphiên bản sẽ cung cấp cho bạn John Smith , có thêm một khoảng trống. Như bạn có thể tưởng tượng, điều này thường không mong muốn. Cách khắc phục cho điều này là sử dụng mapnhư vậy:[patient1.firstName, patient1.middleName, patient1.lastName].map(el => el).join(" ");
General_Twyckenham

@General_Twyckenham aah Tôi hiểu ý bạn. Nắm bắt tốt. Ngoài ra, nó nên được lọc và không phải bản đồ để loại bỏ không gian thừa đó. Tôi sẽ chỉnh sửa câu trả lời của mình, cảm ơn.
Dhruv Prakash

Rất tiếc - vâng, đó filterlà chức năng mà tôi muốn nói.
General_Twyckenham

Và theo cuộc thảo luận này, nối chuỗi nhanh hơn nối mảng. stackoverflow.com/questions/7299010/…
Michael Harley
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.