Javascript heredoc


109

Tôi cần một cái gì đó như heredoc trong JavaScript. Bạn có bất kỳ ý tưởng cho điều này? Tôi cần chức năng trình duyệt chéo.

Tôi đã tìm thấy cái này:

heredoc = '\
<div>\
    <ul>\
        <li><a href="#zzz">zzz</a></li>\
    </ul>\
</div>';

Tôi nghĩ rằng nó sẽ làm việc cho tôi. :)


6
Bản sao của stackoverflow.com/questions/805107/… có một số câu trả lời chi tiết hơn.
Chadwick

4
Phải thêm "\" khiến tôi lần nào cũng phải cau mày. Imho, không có cú pháp bình thường cho chuỗi nhiều dòng là hoàn toàn không hợp lý. Và họ có thể đã thêm nó vào bất kỳ phiên bản nhất định nào, nhưng họ đã không.
Lex

1
Có thể trùng lặp của Tạo chuỗi multiline trong JavaScript
brasofilo

Ngày nay, điều này được thực hiện với các ký tự mẫu như được hiển thị trong bản sao có thể xảy ra (không có câu trả lời cập nhật ở đây).
brasofilo

Câu trả lời:


77

Hãy thử Mẫu chuỗi ES6 , bạn có thể làm những việc như

var hereDoc = `
This
is
a
Multiple
Line
String
`.trim()


hereDoc == 'This\nis\na\nMultiple\nLine\nString'

=> true

Bạn có thể sử dụng tính năng tuyệt vời này ngay hôm nay bằng 6to5 hoặc TypeScript


2
Điều này có thể áp dụng nếu bạn chỉ muốn các chuỗi nhiều dòng. Tuy nhiên, vì bạn không thể thực sự thay đổi biểu tượng bao quanh chuỗi của mình, nên nó không thực sự là heredoc.
Peeyush Kushwaha

3
Như một lưu ý, câu hỏi ban đầu đã được đặt ra cách đây 5 năm trước khi có ES6. Đây là cách thực hành tốt nhất trong tương lai vì hiệu suất cũng tốt hơn.
Henry Tseng

2
@HenryTseng, vậy bạn có gợi ý rằng câu trả lời cho câu hỏi này nên được điều chỉnh cho phù hợp với các công nghệ cổ xưa đã tồn tại 5 năm trước không? Nếu câu hỏi vẫn còn bỏ ngỏ, thì nó xứng đáng được tận dụng các công nghệ mới khi chúng được tạo ra theo thời gian. Bằng cách đó, những người dùng mới gặp vấn đề tương tự có thể tìm thấy thông tin "phi khảo cổ học" tại đây.
asiby

1
Không, tôi đang đưa ra nhận xét tại sao giải pháp đó không nổi bật hơn trước đó. Có vẻ như đây chắc chắn là cách được hỗ trợ trong tương lai nếu không có bất kỳ vấn đề tương thích nào.
Henry Tseng

63

Không, rất tiếc JavaScript không hỗ trợ bất cứ thứ gì như heredoc.


12
Tôi biết nhưng tôi hy vọng để tìm heredoc Hack :)
VeroLom

Một cái gì đó như bình luận chức năng phân tích của (nhưng nó không làm việc trong ie / firefox) =
VeroLom

37

Còn cái này thì sao:

function MyHereDoc(){
/*HERE
<div>
   <p>
      This is written in the HEREDOC, notice the multilines :D.
   </p>
   <p>
      HERE
   </p>
   <p>
      And Here
   </p>
</div>
HERE*/
    var here = "HERE";
    var reobj = new RegExp("/\\*"+here+"\\n[\\s\\S]*?\\n"+here+"\\*/", "m");
    str = reobj.exec(MyHereDoc).toString();
    str = str.replace(new RegExp("/\\*"+here+"\\n",'m'),'').toString();
    return str.replace(new RegExp("\\n"+here+"\\*/",'m'),'').toString();
}

//Usage 
document.write(MyHereDoc());

Chỉ cần thay thế "/ * HERE" và "HERE * /" bằng từ lựa chọn.


4
có phải tất cả các trình duyệt / công cụ đều trả lại nhận xét trong Function.toString ()? đó là rất thông minh
GCB

Hoạt động trong bảng điều khiển của Chrome
Omn

4
Sẽ không hoạt động nếu bạn có nhận xét kết thúc */trong heredoc của mình.
Narigo

2
Tôi khuyên bạn nên sử dụng câu trả lời của Nate Ferrero, vì anh ấy là một ví dụ tinh tế hơn và được tối ưu hóa. Của tôi sử dụng 3 cuộc gọi regEx riêng biệt và là bằng chứng về khái niệm.
Zv_oDD

1
Rất thông minh ... nhưng bạn không thể đảm bảo nó sẽ hoạt động trong tương lai. Nó quá phụ thuộc vào việc thực hiện để trở thành một thực hành tốt.
Pierre-Olivier Vares

33

Dựa trên câu trả lời của Zv_oDD, tôi đã tạo một hàm tương tự để sử dụng lại dễ dàng hơn.

Cảnh báo: Đây là một tính năng không chuẩn của nhiều trình thông dịch JS và có thể sẽ bị xóa vào một lúc nào đó, nhưng vì tôi đang xây dựng một tập lệnh để chỉ sử dụng trong Chrome nên tôi đang sử dụng nó! Đừng bao giờ dựa vào điều này cho các trang web dành cho khách hàng!

// Multiline Function String - Nate Ferrero - Public Domain
function heredoc(fn) {
  return fn.toString().match(/\/\*\s*([\s\S]*?)\s*\*\//m)[1];
};

Sử dụng:

var txt = heredoc(function () {/*
A test of horrible
Multi-line strings!
*/});

Lợi nhuận:

"A test of horrible
Multi-line strings!"

Ghi chú:

  1. Văn bản được cắt ở cả hai đầu, vì vậy bất kỳ khoảng trắng thừa nào ở hai đầu đều được.

Chỉnh sửa:

2/2/2014 - đã thay đổi để hoàn toàn không gây rối với nguyên mẫu Hàm và sử dụng tên heredoc để thay thế.

5/26/2017 - khoảng trắng được cập nhật để phản ánh các tiêu chuẩn mã hóa hiện đại.


1
Tôi sẽ sử dụng hereDoc () làm tên hàm của mình, nhưng mã này hoạt động tốt khi tải kết xuất nhật ký dòng 40k của tôi vào một biến trong bảng điều khiển của Chrome
Omn

Tại sao bạn lại tạo một phiên bản của một hàm và truy cập vào thuộc tính __ proto __ không dùng nữa? Tại sao không chỉ làm Function.prototype.str = function () {...}?
John Kurlak

@JohnKurlak thậm chí còn tốt hơn! Tôi không nghĩ rằng tôi đã biết điều đó có thể xảy ra khi tôi viết câu trả lời.
Nate Ferrero

2
@NateFerrero - Câu trả lời tuyệt vời, cảm ơn! Đã thêm một phần mở rộng của riêng tôi làm câu trả lời riêng.
Andrew Cheong

Trên Android của tôi, nexus 4, chạy 5.0.1, tính năng này không còn hoạt động trên Chrome nữa. Vì một số lý do, nó đang xóa khoảng trắng và nhận xét. Tôi không thể biết liệu đây có phải là một cài đặt hay không, nhưng chắc chắn là ở phía khách hàng. Bất kỳ ý tưởng cho một cách giải quyết?
MLU

19

Tùy thuộc vào hương vị của công cụ JS / JS bạn đang chạy (SpiderMonkey, AS3), bạn có thể chỉ cần viết XML nội tuyến, vào đó bạn có thể đặt văn bản trên nhiều dòng, như heredoc:

var xml = <xml>
    Here 
    is 
    some 
    multiline 
    text!
</xml>

console.log(xml.toXMLString())
console.log(xml.toString()) // just gets the content

13

Chuỗi mẫu ES6 có tính năng heredoc.

Bạn có thể khai báo các chuỗi được bao bởi dấu tích ngược (``) và có thể được mở rộng qua nhiều dòng.

var str = `This is my template string...
and is working across lines`;

Bạn cũng có thể bao gồm các biểu thức bên trong Chuỗi mẫu. Chúng được biểu thị bằng dấu Dollar và dấu ngoặc nhọn ( ${expression}).

var js = "Java Script";
var des = `Template strings can now be used in ${js} with lot of additional features`;

console.log(des); //"Template strings can now be used in Java Script with lot of additional features"

Trên thực tế, có nhiều tính năng hơn như Tagged Temple Strings và Raw Strings trong đó. Vui lòng tìm tài liệu tại

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings


8

Tôi cảm thấy không ổn khi viết một câu trả lời riêng chỉ đơn thuần là một phần mở rộng cho câu trả lời của @ NateFerrero , nhưng tôi cảm thấy việc chỉnh sửa câu trả lời của anh ấy cũng không phù hợp, vì vậy vui lòng ủng hộ @NateFerrero nếu câu trả lời này hữu ích với bạn.

tl; dr — Dành cho những người muốn sử dụng nhận xét khối bên trong heredoc của họ ...

Tôi chủ yếu cần heredocs Javascript để lưu trữ một khối CSS, ví dụ:

var css = heredoc(function() {/*
    /**
     * Nuke rounded corners.
     */
    body div {
        border-top-left-radius: 0 !important;
        border-top-right-radius: 0 !important;
        border-bottom-right-radius: 0 !important;
        border-bottom-left-radius: 0 !important;
    }
*/});

Tuy nhiên, như bạn có thể thấy, tôi thích nhận xét CSS của mình, và thật không may (như được gợi ý bởi tô sáng cú pháp) phần đầu tiên */kết thúc nhận xét tổng thể, phá vỡ heredoc.


Đối với mục đích cụ thể này (CSS), cách giải quyết của tôi là thêm

.replace(/(\/\*[\s\S]*?\*) \//g, '$1/')

vào chuỗi bên trong @ NateFerrero's heredoc; ở dạng hoàn chỉnh:

function heredoc (f) {
    return f.toString().match(/\/\*\s*([\s\S]*?)\s*\*\//m)[1].replace(/(\/\*[\s\S]*?\*) \//g, '$1/');
};

và sử dụng nó bằng cách thêm một khoảng trắng giữa */cho các nhận xét khối "bên trong", như sau:

var css = heredoc(function() {/*
    /**
     * Nuke rounded corners.
     * /
    body div {
        border-top-left-radius: 0 !important;
        border-top-right-radius: 0 !important;
        border-bottom-right-radius: 0 !important;
        border-bottom-left-radius: 0 !important;
    }
*/});

Đơn replacegiản là tìm /* ... * /và loại bỏ không gian để tạo /* ... */, do đó bảo toàn heredoc cho đến khi được gọi.


Tất nhiên, bạn có thể xóa hoàn toàn các nhận xét bằng cách sử dụng

.replace(/\/\*[\s\S]*?\* \//g, '')

Bạn cũng có thể hỗ trợ //nhận xét nếu bạn thêm chúng vào chuỗi:

.replace(/^\s*\/\/.*$/mg, '')

Ngoài ra, bạn có thể làm điều gì đó ngoài khoảng trắng duy nhất giữa */, chẳng hạn như -:

    /**
     * Nuke rounded corners.
     *-/

nếu bạn chỉ cập nhật regex một cách thích hợp:

.replace(/(\/\*[\s\S]*?\*)-\//g, '$1/')
                          ^

Hoặc có thể bạn muốn một lượng khoảng trắng tùy ý thay vì một khoảng trắng?

.replace(/(\/\*[\s\S]*?\*)\s+\//g, '$1/')
                          ^^^

2
Mát mẻ! Đó là hạn chế đã biết với phương pháp của tôi, tôi như nó :)
Nate Ferrero

8

Bạn có thể sử dụng CoffeeScript , một ngôn ngữ biên dịch thành JavaScript. Mã biên dịch 1-1 thành JS tương đương và không có diễn giải trong thời gian chạy.

Và tất nhiên, nó có heredocs :)


24
Câu trả lời chính xác là không. CoffeeScript và EJS có thể được sử dụng làm đề xuất.
alvincrespo

4
CoffeeScript là câu trả lời chính xác cho hầu hết các vấn đề về JS mà tôi gặp phải. Nếu bạn viết nhiều hơn một lượng JS tầm thường (và bạn coi trọng thời gian và năng lượng của mình) thì bạn nợ chính mình để sử dụng nó.
Brandon

5
Tôi nghĩ đây là một câu trả lời hay vì nó cung cấp một cách dễ dàng để tránh sự thiếu vắng của heredoc trong javascript. Tiết kiệm cho tôi rất nhiều thời gian.
Stofke

3
Nếu bạn chỉ muốn có một vài mẩu tin nhưng không muốn thực sự viết nó: coffeescript.org và sử dụng nút "Thử Coffeescript".
jcollum

1
Đây là một câu trả lời nhiều hơn câu trả lời được đánh giá cao nhất, về cơ bản chỉ là ... "không". Tôi ghét những câu trả lời kiểu đó.
Matt Fletcher

7

ES5 và các phiên bản trước đó

(function(){/**
some random
multi line
text here
**/}).toString().slice(15,-5);

ES6 và các phiên bản mới hơn

`some random
multi line
text here`

kết quả

some random
multi line
text here

tốt nhất câu trả lời đơn giản
Benjamin

1
Kiểu cũ là một vụ hack cực kỳ tàn bạo: /
Shayne

1

Bạn có thể sử dụng Macro Sweet.js để thêm nó giống như vậy, như được tạo bởi Tim Disney trong bài đăng này

Lưu ý rằng phương pháp này sử dụng dấu gạch ngược làm dấu phân cách chuỗi thay thế:

let str = macro {
    case {_ $template } => {
        var temp = #{$template}[0];
        var tempString = temp.token.value.raw;
        letstx $newTemp = [makeValue(tempString, #{here})];
        return #{$newTemp}
    }
}

str `foo bar baz`

1

Như những người khác đã nói, chuỗi mẫu ES6 cung cấp cho bạn hầu hết những gì heredocs truyền thống cung cấp.

Nếu bạn muốn tiến thêm một bước và sử dụng chuỗi mẫu được gắn thẻ, thì đây theredoclà một chức năng tiện ích tuyệt vời cho phép bạn thực hiện điều này:

if (yourCodeIsIndented) {
  console.log(theredoc`
    Theredoc will strip the
    same amount of indentation
    from each line.

      You can still indent
      further if you want.

    It will also chop off the
    whitespace-only first and
    last lines.
  `)
}

0

Nếu bạn có một số html và jQuery trong tay và chuỗi là HTML hợp lệ, điều này có thể hữu ích:

<div id="heredoc"><!--heredoc content
with multiple lines, even 'quotes' or "double quotes",
beware not to leave any tag open--></div>
<script>
var str = (function() {
   var div = jQuery('#heredoc');
   var str = div.html();
   str = str.replace(/^<\!--/, "").toString();
   str = str.replace(/-->$/, "").toString();
   return str;
})();
</script>

Nếu văn bản có chú thích "<! - ->" ở giữa, nó cũng hoạt động, nhưng một phần của văn bản có thể hiển thị. Đây là fiddle: https://jsfiddle.net/hr6ar152/1/


0
// js heredoc - http://stackoverflow.com/a/32915549/466363
// a function with comment with eval-able string, use it just like regular string

function extractFuncCommentString(func,comments) {
  var matches = func.toString().match(/function\s*\(\)\s*\{\s*\/\*\!?\s*([\s\S]+?)\s*\*\/\s*\}/);
  if (!matches) return undefined;
  var str=matches[1];

   // i have made few flavors of comment removal add yours if you need something special, copy replacement lines from examples below, mix them
  if(comments===1 )
  {
   // keep comments, in order to keep comments  you need to convert /**/ to / * * / to be able to put them inside /**/ like /*    / * * /    */
   return (
    str
   .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */ 
   )
  }
  else if(comments===2)
  {
   // keep comments and replace singleline comment to multiline comment
   return (
    str
   .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */ 
   .replace(/\/\/(.*)/g,"/*$1*/")          //           change   //abc to  /*abc*/
   )
  }
  else if(comments===3)
  {
   // remove comments
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"") //       match / * abc * /
      .replace(/\/\/(.*)/g,"")             // match //abc
     )
  }
  else if(comments===4)
  {
   // remove comments and trim and replace new lines with escape codes
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"") //       match / * abc * /
      .replace(/\/\/(.*)/g,"")             // match //abc
      .trim() // after removing comments trim and:
      .replace(/\n/g,'\\n').replace(/\r/g,'\\r') // replace new lines with escape codes. allows further eval() of the string, you put in the comment function: a quoted text but with new lines
     )
  }
  else if(comments===5)
  {
   // keep comments comments and replace strings, might not suit when there are spaces or comments before and after quotes 
   // no comments allowed before quotes of the string
   return (
      str
      .replace(/\/\s\*([\s\S]*?)\*\s\//g,"/*$1*/") //       change   / * text * /  to   /* text */
      .replace(/\/\/(.*)/g,"/*$1*/")          //           change   //abc to  /*abc*/
      .trim() // trim space around quotes to not escape it and:
      .replace(/\n/g,'\\n').replace(/\r/g,'\\r') // replace new lines with escape codes. allows further eval() of the string, you put in the comment function: a quoted text but with new lines
     )
  }
  else 
  return str
}

thí dụ

var week=true,b=123;
var q = eval(extractFuncCommentString(function(){/*!

// this is a comment     


'select 

/ * this
is a multiline 
comment * /

 a
,b  // this is a comment  
,c
from `table`
where b='+b+' and monthweek="'+(week?'w':'m')+'" 
//+' where  a=124
order by a asc
'
*/},4));

với bộ nhớ cache: - tạo một chức năng mẫu đơn giản và lưu chức năng: (hoạt động nhanh lần thứ hai)

var myfunction_sql1;
function myfunction(week,a){


    if(!myfunction_sql1) eval('myfunction_sql1=function(week,a){return ('+extractFuncCommentString(function(){/*!
'select 

/ * this
is a multiline 
comment * /

 a
,b  // this is a comment  
,c
from `table`
where b='+b+' and monthweek="'+(week?'w':'m')+'" 
//+' where  a=124
order by a asc

'*/},4)+')}');
    q=myfunction_sql1(week,a);
    console.log(q)
}
myfunction(true,1234)

1
Kết quả khá khác nhau trong FF và Chrome.
Dave Newton

khác biệt là gì? Tôi vừa thử nghiệm trong Chrome và FF và tôi nhận được kết quả chính xác. Ngoại trừ việc trong Chrome không có dòng mới trong Bảng điều khiển của Chrome Nếu bạn chỉ nhập tên var. nhưng biến giống nhau. Có thể in với dòng mới với console.log ()
Shimon Doodkin

0

Tôi đăng phiên bản này vì nó tránh việc sử dụng regex cho những thứ quá tầm thường.

IMHO regex là một sự xáo trộn được tạo ra như một trò đùa thực tế giữa các nhà phát triển perl. phần còn lại của cộng đồng đã coi chúng một cách nghiêm túc và bây giờ chúng ta phải trả giá, hàng thập kỷ sau. không sử dụng regex, ngoại trừ tính tương thích ngược với mã kế thừa. Ngày nay không có lý do gì để viết mã mà con người không thể đọc và hiểu được ngay lập tức. regex vi phạm nguyên tắc này ở mọi cấp độ.

Tôi cũng đã thêm một cách để thêm kết quả vào trang hiện tại, không phải điều này được yêu cầu.

function pretty_css () {
/*
    pre { color: blue; }

*/
}
function css_src (css_fn) {
   var css = css_fn.toString();
   css = css.substr(css.indexOf("/*")+2);
   return css.substr(0,css.lastIndexOf("*/")).trim();
}

function addCss(rule) {
  let css = document.createElement('style');
  css.type = 'text/css';
  if (css.styleSheet) css.styleSheet.cssText = rule; // Support for IE
  else css.appendChild(document.createTextNode(rule)); // Support for the rest
  document.getElementsByTagName("head")[0].appendChild(css);
}

addCss(css_src(pretty_css));

document.querySelector("pre").innerHTML=css_src(pretty_css);
<pre></pre>

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.