Кто-нибудь может объяснить это странное поведение JS относительно конкатенации строк? - PullRequest
10 голосов
/ 28 марта 2012

Я только что отправил это в суть: https://gist.github.com/2228570

var out = '';

function doWhat(){
    out += '<li>';
    console.log(out === '<li>'); // at this point, out will equal '<li>'
    return '';
}

out += doWhat();
console.log(out, out === '<li>');
// I expect out to == '<li>', but it's actually an empty string!?

Это странное поведение, у кого-нибудь есть объяснение?Это сложная вещь для Google.Также не имеет значения, если вы используете out += или out = out +.

EDIT: @paislee создал JSFiddle, который демонстрирует, как если doWhat находится на отдельной строке, он ведет себя как ожидалось: http://jsfiddle.net/paislee/Y4WE8/

Ответы [ 4 ]

7 голосов
/ 28 марта 2012

Похоже, вы ожидаете, что doWhat будет вызван до того, как += будет оценен.

Но последовательность будет такой:

out += doWhat();      // original line
out = out + doWhat(); // expand `+=`
out = '' + doWhat();  // evaluate `out`, which is currently an empty string
out = '' + '';        // call `doWhat`, which returns another empty string
out = '';             // result

out += '<li>'; inside doWhat обновляет переменную, но слишком поздно, чтобы иметь длительный эффект.

6 голосов
/ 28 марта 2012

Путаница в том, что вы ожидаете, что doWhat() также изменит out напрямую.Очевидно, значение, к которому вы добавите, извлекается до вызова этой функции.

Вот логика:

  1. Получить значение out ('')
  2. Вызовите doWhat() и добавьте результат к первому значению ('' + '' = '')
  3. Назначьте результат на out ('')

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

2 голосов
/ 28 марта 2012

Представьте себе это так:

// out is undefined
var out = '';
// out is ''
function doWhat(){
 out += '<li>';
 // out is '<li>';
 return '';
}
out = out + doWhat();
// out += doWhat(); is the same as:
// out = out + doWhat(); is the same as :
// out = '' + doWhat; because the value of `out` is read when `out` is first found
// out is ''

И линеаризованные:

// out is undefined
var out = '';
// out is ''
out += '<li>';
// out is '<li>';
out = '' + ''; // first '' is value of `out` before function is called, second is what the function returns
// out is ''

Решение

var out = '';
function doWhat(){
 out += '<li>';
 return '';
}
out = doWhat() + out; // Note `out` is *after* `doWhat()`

TL; DR

В настоящее времяВаш код оценивается так же, как:

out = out + doWhat();

Это считывает значение out до вызова doWhat().Чтобы заставить его работать так, как вы ожидаете, просто измените порядок:

out = doWhat() + out;

Это будет считывать значение out после doWhat(), как вы ожидаете.

1 голос
/ 28 марта 2012

Как сказал выше Джонатан, вы возвращаете пустую строку из функции, поэтому, даже если вы изменяете глобальную переменную, добавляя '<li>' к out внутри doWhat, javascript добавит возвращаемое значение из функции к значению out при вызове функции.

Вы также можете просто сделать:

var out = '';

function doWhat(){
    out += '<li>';
    return true;
}

doWhat();

Есть ли какая-то особая причина, по которой вам нужно добавлять что-либо в строку как внутри функции, так и после того, как возвращается ее значение?

[править]

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

var out = '', temp;

function doWhat(){
   out += '<li>';
}

out += typeof (temp = doWhat()) === 'undefined' ? '' : temp;

Из этой презентации значение temp всегда будет неопределенным, потому что функция не возвращает ничего, что можно было бы ввести. Если вы планируете, чтобы функция иногда возвращала значение, которое вы затем добавляете, вы можете достичь того, что ищете, разбив его на две строки в конце:

var out = '', temp;
function doWhat(){
    out += '<li>';
}
temp = doWhat();
out += typeof (temp === undefined) ? '' : temp;

Это немного неловко, и я, вероятно, попытался бы переместить оба добавления в функцию.

var out = '';
function doWhat () {
   out += '<li>';
   if (some condition is met) { out += 'some extra string'; }
}
doWhat();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...