Объединение строк с операторами `if` в JavaScript

Я пытаюсь настроить скрипт для объединения некоторых переменных внутри строки если они существуют, чтобы поместить соответствующие теги метаданных в отображаемый HTML-документ.

Мой код конкатенации:

data = "<html>\n<head>\n" + "</head>\n<body>\n\n" + paras.join("\n\n") + "\n\n</body>\n</html>";

Я пытаюсь добавить в него операторы if, подобные следующим (между первым и вторым элементами):

if (typeof metadata_title !== "undefined") {
    "<title>" + metadata_title + "</title>\n"
}
if (typeof metadata_author !== "undefined") {
    "<meta name=\"author\" content=\"" + metadata_author + "\"></meta>\n"
}
if (typeof metadata_date !== "undefined") {
    "<meta name=\"date\" content=\"" + metadata_date + "\"></meta>\n"
}

Но я не могу добавить ни одно из этих утверждений непосредственно в код конкатенации (выдает ошибку: Unexpected token ().

Как лучше всего мне добавить такие операторы в мою строку конкатенации?


person 木川 炎星    schedule 08.09.2011    source источник


Ответы (4)


Я бы использовал тернарный оператор:

data = "<html>\n"
     + "<head>\n" 
     + ( typeof metadata_title  !== "undefined" ?  "<title>" + metadata_title + "</title>\n"                             : "" )
     + ( typeof metadata_author !== "undefined" ?  "<meta name=\"author\" content=\"" + metadata_author + "\"></meta>\n" : "" )
     + ( typeof metadata_date   !== "undefined" ?  "<meta name=\"date\" content=\"" + metadata_date + "\"></meta>\n"     : "" )
     + "</head>\n"
     + "<body>\n"
     + "\n"
     + paras.join("\n\n")
     + "\n"
     + "\n"
     + "</body>\n"
     + "</html>"
;
person bluish    schedule 08.09.2011
comment
‹ запутался в использовании typeof в этом случае. Почему бы просто не проверить, является ли var является undefined?.. - person Demian Brecht; 08.09.2011
comment
В исключительных случаях (var undefined = 'test';) результат неверный. Использование typeof экономит. - person scessor; 08.09.2011
comment
Если одна из переменных вообще не определена, вы получите ReferenceError. Я думаю, это то, что имел в виду ОП. Конечно, у вас все в порядке, если все три метаданных определены. - person Ray Toal; 08.09.2011

Я мог бы сделать что-то немного другое (немного больше похожее на шаблоны), главным образом потому, что я ненавижу составной HTML, сделанный с помощью Javascript:

var metadata_title = "Hello";
var metadata_author = "Me";
var metadata_date = "2011-09-07";

var template = "<html>\
            <head>\
                <title>#title#</title>\
                <meta name=\"author\" content=\"#author#\"></meta>\
                <meta name=\"date\" content=\"#date#\"></meta>\
            </head>\
            <body>\
            </body>\
            </html>";

var data = template.replace("#title#", metadata_title != undefined ? metadata_title : "")
                   .replace("#author#", metadata_author != undefined ? metadata_author : "")
                   .replace("#date#", metadata_date != undefined ? metadata_date : "");

Конечно, есть очень небольшие дополнительные накладные расходы, но для меня это гораздо более читабельно.

person Demian Brecht    schedule 08.09.2011
comment
Как бы вы получили paras здесь? (Не то, чтобы это было сложно; я просто хотел бы посмотреть, что вы придумали бы в отсутствие настоящей машины для соблазнения. Удачи.) - person Ray Toal; 08.09.2011
comment
Если я что-то упустил (уже поздно и мне нужно спать), я бы, скорее всего, просто добавил #paras# между тегами body и заменил его так же, как заменяются другие элементы. join просто возвращает a string, поэтому я предполагаю, что это сработает. - person Demian Brecht; 08.09.2011

Соберите весь документ в массив, затем соедините с помощью "\n" в конце. (Обоснование этого, конечно, состоит в том, чтобы не было много новых строк, разбросанных повсюду! И если вы используете IE7 или меньше, Array#join значительно быстрее, чем повторяющаяся конкатенация строк.)

Код здесь: http://jsfiddle.net/ZCbCZ/

ОБНОВЛЕНИЕ Я забыл включить "paras" в первую скрипку. Код с параграфами находится здесь: http://jsfiddle.net/U8325/1/

Для тех, кто не хочет щелкать и пробовать, вот скрипт:

// Not going to define metadata_author just to be saved by typeof :-)
var metadata_title = "Hello";
var metadata_date = "2011-09-07";

// Okay 3 paras for fun
var paras = ["<p>paragraph1</p>", "<p>paragraph2</p>", "<p>paragraph3</p>"];

data = ["<html>", "<head>"]

if (typeof metadata_title !== "undefined") {
    data.push("<title>" + metadata_title + "</title>");
}
if (typeof metadata_author !== "undefined") {
    data.push("<meta name=\"author\" content=\"" + metadata_author + "\"></meta>");
}
if (typeof metadata_date !== "undefined") {
    data.push("<meta name=\"date\" content=\"" + metadata_date + "\"></meta>");
}

data.push("</head>");
data.push("<body>");
paras.forEach(function (p) {data.push(p);});   // Requires ES5; use a for-loop if you don't have it
data.push("</body>");
data.push("<html>");
data = data.join("\n");
alert(data);
person Ray Toal    schedule 08.09.2011

Мне понравилась читабельность ответа Демьяна Брехта, но я бы изменил строку только на regex вместо этого, поскольку функция replace() заменяет только первое совпадение (подробнее см. здесь: JavaScript .replace заменяет только первое совпадение)

var metadata_title = "Hello";
var metadata_author = "Me";
var metadata_date = "2011-09-07";

var template = "<html>\
            <head>\
                <title>#title#</title>\
                <meta name=\"author\" content=\"#author#\"></meta>\
                <meta name=\"date\" content=\"#date#\"></meta>\
            </head>\
            <body>\
            </body>\
            </html>";

var data = template.replace(/#title#/g, metadata_title != undefined ? metadata_title : "")
                   .replace(/#author#/g, metadata_author != undefined ? metadata_author : "")
                   .replace(/#date#/g, metadata_date != undefined ? metadata_date : "");
person Francisco Costa    schedule 12.10.2013