如何在JavaScript中反向字符串?

在JavaScript中,当字符串被传递给带有返回语句的函数时,如何反转字符串,而不使用内置函数(.reverse().charAt()等)?

674985 次浏览
String.prototype.reverse_string=function() {return this.split("").reverse().join("");}

String.prototype.reverse_string = function() {
var s = "";
var i = this.length;
while (i>0) {
s += this.substring(i-1,i);
i--;
}
return s;
}
function reverseString(string) {
var reversedString = "";
var stringLength = string.length - 1;
for (var i = stringLength; i >= 0; i--) {
reversedString += string[i];
}
return reversedString;
}

只要你处理的是简单的ASCII字符,并且你很乐意使用内置函数,这就可以工作:

function reverse(s){
return s.split("").reverse().join("");
}

如果您需要一个支持UTF-16或其他多字节字符的解决方案,请注意这个函数会给出无效的unicode字符串,或者看起来很滑稽的有效字符串。您可能需要考虑而是这个答案

[…s]是Unicode感知的,一个小的编辑给出:-

function reverse(s){
return [...s].reverse().join("");
}

你可以尝试这样做。我相信还有重构的空间。我无法使用分裂函数。也许有人知道不分裂的方法。

代码设置,可以把它放在你的。js库

使用它的代码(有客户端代码,只是因为它在浏览器中测试过):

var sentence = "My Stack is Overflowing."
document.write(sentence.reverseLetters() + '<br />');
document.write(sentence.reverseWords() + '<br />');

代码片段:

String.prototype.aggregate = function(vals, aggregateFunction) {


var temp = '';
for (var i = vals.length - 1; i >= 0; i--) {
temp = aggregateFunction(vals[i], temp);
}
return temp;
}


String.prototype.reverseLetters = function() {
return this.aggregate(this.split(''),
function(current, word) {
return word + current;
})
}


String.prototype.reverseWords = function() {
return this.aggregate(this.split(' '),
function(current, word) {
return word + ' ' + current;
})
}


var sentence = "My Stack is Overflowing."
document.write(sentence.reverseLetters() + '<br />');
document.write(sentence.reverseWords() + '<br />');

另一个变体(它在IE中工作吗?):

String.prototype.reverse = function() {
for (i=1,s=""; i<=this.length; s+=this.substr(-i++,1)) {}
return s;
}

编辑:

这是不使用内置函数的:

String.prototype.reverse = function() {
for (i=this[-1],s=""; i>=0; s+=this[i--]) {}
return s;
}

注意:this[-1]保存字符串的长度。

然而,不可能将字符串反向,因为赋值给 单个数组元素不能与String对象(protected?)一起工作。也就是说,你可以赋值,但结果字符串不会改变

整个“将字符串反向”是一个过时的C程序员面试问题,被他们面试的人(可能是为了报复?)会问。不幸的是,它的“到位”部分不再起作用,因为几乎所有托管语言(JS, c#等)中的字符串都使用不可变字符串,因此无法在不分配任何新内存的情况下移动字符串。

虽然上面的解决方案确实反转了字符串,但它们在不分配更多内存的情况下不会这样做,因此不满足条件。您需要直接访问分配的字符串,并能够操作其原始内存位置,以便将其反向。

就我个人而言,我真的很讨厌这类面试问题,但遗憾的是,我相信在未来几年里我们还会继续看到它们。

var str = "IAMA JavaScript Developer";
var a=str.split(''), b = a.length;
for (var i=0; i<b; i++) {
a.unshift(a.splice(1+i,1).shift())
}
a.shift();
alert(a.join(''));

我认为这是最简单的方法

var reverse = function(str) {
var arr = [];
    

for (var i = 0, len = str.length; i <= len; i++) {
arr.push(str.charAt(len - i))
}


return arr.join('');
}


console.log(reverse('I want a 🍺'));

看来我已经迟到3年了…

不幸的是,正如已经指出的那样,你不能。看到# EYZ0

你能做的下一个最好的事情是创建一个“视图”或“包装器”,它接受一个字符串并重新实现你正在使用的字符串API的任何部分,但假装字符串是反向的。例如:

var identity = function(x){return x};


function LazyString(s) {
this.original = s;


this.length = s.length;
this.start = 0; this.stop = this.length; this.dir = 1; // "virtual" slicing
// (dir=-1 if reversed)


this._caseTransform = identity;
}


// syntactic sugar to create new object:
function S(s) {
return new LazyString(s);
}


//We now implement a `"...".reversed` which toggles a flag which will change our math:


(function(){ // begin anonymous scope
var x = LazyString.prototype;


// Addition to the String API
x.reversed = function() {
var s = new LazyString(this.original);


s.start = this.stop - this.dir;
s.stop = this.start - this.dir;
s.dir = -1*this.dir;
s.length = this.length;


s._caseTransform = this._caseTransform;
return s;
}


//We also override string coercion for some extra versatility (not really necessary):


// OVERRIDE STRING COERCION
//   - for string concatenation e.g. "abc"+reversed("abc")
x.toString = function() {
if (typeof this._realized == 'undefined') {  // cached, to avoid recalculation
this._realized = this.dir==1 ?
this.original.slice(this.start,this.stop) :
this.original.slice(this.stop+1,this.start+1).split("").reverse().join("");


this._realized = this._caseTransform.call(this._realized, this._realized);
}
return this._realized;
}


//Now we reimplement the String API by doing some math:


// String API:


// Do some math to figure out which character we really want


x.charAt = function(i) {
return this.slice(i, i+1).toString();
}
x.charCodeAt = function(i) {
    return this.slice(i, i+1).toString().charCodeAt(0);
}


// Slicing functions:


x.slice = function(start,stop) {
// lazy chaining version of https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/slice


if (stop===undefined)
stop = this.length;


var relativeStart = start<0 ? this.length+start : start;
var relativeStop = stop<0 ? this.length+stop : stop;


if (relativeStart >= this.length)
relativeStart = this.length;
if (relativeStart < 0)
relativeStart = 0;


if (relativeStop > this.length)
relativeStop = this.length;
if (relativeStop < 0)
relativeStop = 0;


if (relativeStop < relativeStart)
relativeStop = relativeStart;


var s = new LazyString(this.original);
s.length = relativeStop - relativeStart;
s.start = this.start + this.dir*relativeStart;
s.stop = s.start + this.dir*s.length;
s.dir = this.dir;


//console.log([this.start,this.stop,this.dir,this.length], [s.start,s.stop,s.dir,s.length])


s._caseTransform = this._caseTransform;
return s;
}
x.substring = function() {
// ...
}
x.substr = function() {
// ...
}


//Miscellaneous functions:


// Iterative search


x.indexOf = function(value) {
for(var i=0; i<this.length; i++)
if (value==this.charAt(i))
return i;
return -1;
}
x.lastIndexOf = function() {
for(var i=this.length-1; i>=0; i--)
if (value==this.charAt(i))
return i;
return -1;
}


// The following functions are too complicated to reimplement easily.
// Instead just realize the slice and do it the usual non-in-place way.


x.match = function() {
var s = this.toString();
return s.apply(s, arguments);
}
x.replace = function() {
var s = this.toString();
return s.apply(s, arguments);
}
x.search = function() {
var s = this.toString();
return s.apply(s, arguments);
}
x.split = function() {
var s = this.toString();
return s.apply(s, arguments);
}


// Case transforms:


x.toLowerCase = function() {
var s = new LazyString(this.original);
s._caseTransform = ''.toLowerCase;


s.start=this.start; s.stop=this.stop; s.dir=this.dir; s.length=this.length;


return s;
}
x.toUpperCase = function() {
var s = new LazyString(this.original);
s._caseTransform = ''.toUpperCase;


s.start=this.start; s.stop=this.stop; s.dir=this.dir; s.length=this.length;


return s;
}


})() // end anonymous scope

演示:

> r = S('abcABC')
LazyString
original: "abcABC"
__proto__: LazyString


> r.charAt(1);       // doesn't reverse string!!! (good if very long)
"B"


> r.toLowerCase()    // must reverse string, so does so
"cbacba"


> r.toUpperCase()    // string already reversed: no extra work
"CBACBA"


> r + '-demo-' + r   // natural coercion, string already reversed: no extra work
"CBAcba-demo-CBAcba"

最重要的是——下面是用纯数学来完成的,每个角色只访问一次,而且是在必要的时候:

> 'demo: ' + S('0123456789abcdef').slice(3).reversed().slice(1,-1).toUpperCase()
"demo: EDCBA987654"


> S('0123456789ABCDEF').slice(3).reversed().slice(1,-1).toLowerCase().charAt(3)
"b"

如果应用于一个非常大的字符串,如果您只取其中相对较小的部分,则可以节省大量的时间。

这样做是否值得(而不是像大多数编程语言那样反向复制)在很大程度上取决于您的用例以及您如何有效地重新实现字符串API。例如,如果您只想做字符串索引操作,或者使用小的# eyz0或# eyz1,这将节省您的空间和时间。然而,如果你打算打印大的反向切片或子字符串,节省的成本可能很小,甚至比完整复制还要少。你的“反转”字符串也不会有string类型,尽管你可以通过原型来伪造它。

上面的演示实现创建了一个ReversedString类型的新对象。它是原型化的,因此相当高效,几乎只需要最少的工作和最小的空间开销(共享原型定义)。它是一个涉及延迟切片的惰性实现。无论何时执行像.slice.reversed这样的函数,它都将执行索引数学。最后,当您提取数据时(通过隐式调用.toString().charCodeAt(...)等),它将以“智能”方式应用这些数据,尽可能少地接触数据。

注意:上面的字符串API是一个例子,可能不能完美地实现。你也可以只使用你需要的1-2个函数。

function reverse_string(string)
{
var string;


var len = string.length;


var stringExp = string.split('');
var i;
for (i = len-1; i >=0;i--)
{
var result = document.write(stringExp[i]);
}


return result;
}


reverse_string("This is a reversed string");

//输出:gnirts desrever si sihT

下面的技巧(或类似的)在JavaScript中常用来反转字符串:

// Don’t use this!
var naiveReverse = function(string) {
return string.split('').reverse().join('');
}

事实上,到目前为止,所有的答案都是这种模式的变体。然而,这种解决方案存在一些问题。例如:

naiveReverse('foo 𝌆 bar');
// → 'rab �� oof'
// Where did the `𝌆` symbol go? Whoops!

如果你想知道为什么会这样,阅读JavaScript的内部字符编码。(𝌆是一个星体符号,JavaScript将它公开为两个独立的代码单元。)

但还有更多:

// To see which symbols are being used here, check:
// http://mothereff.in/js-escapes#1ma%C3%B1ana%20man%CC%83ana
naiveReverse('mañana mañana');
// → 'anãnam anañam'
// Wait, so now the tilde is applied to the `a` instead of the `n`? WAT.

以下是测试反向实现的一个很好的字符串:

'foo 𝌆 bar mañana mañana'

为什么?因为它包含一个星体符号(𝌆)(即在JavaScript中由代理对表示)和一个组合标记(最后一个mañana中的实际上由两个符号组成:U+006E拉丁小字母N和U+0303组合波浪号)。

代理符对出现的顺序不能颠倒,否则星体符号将不再出现在“颠倒”字符串中。这就是为什么在前面示例的输出中看到了��标记。

组合标记总是应用于前一个符号,所以你必须把两个主符号(U+006E拉丁小字母N)作为一个整体来对待组合标记(U+0303 combined波浪号)。颠倒它们的顺序将导致组合标记与字符串中的另一个符号配对。这就是示例输出是而不是ñ的原因。

希望这能解释为什么到目前为止所有的答案都是错误的


为了回答您最初的问题——如何在JavaScript中[正确地]反转字符串——,我编写了一个小型JavaScript库,它能够识别unicode的字符串反转。它没有我刚才提到的任何问题。这个库名为< >强Esrever < / >强;它的代码在GitHub上,它可以在几乎任何JavaScript环境中工作。它带有一个shell实用程序/二进制,所以如果你想,你可以很容易地从你的终端反转字符串。

var input = 'foo 𝌆 bar mañana mañana';
esrever.reverse(input);
// → 'anañam anañam rab 𝌆 oof'

至于“就地”部分,请参阅其他答案。

真正的答案是:你不能把它颠倒过来,但是你可以创建一个颠倒过来的新字符串。

就像玩递归的练习一样:有时当你去面试时,面试官可能会问你如何使用递归来做到这一点,我认为“首选答案”可能是“我宁愿不使用递归来做这个,因为它很容易导致堆栈溢出”(因为它是O(n)而不是O(log n)。如果是O(log n),就很难产生堆栈溢出——32级的堆栈可以处理40亿项,因为2 ** 32等于4294967296。但是如果它是O(n),那么它很容易产生堆栈溢出。

有时候面试官还是会问你,“作为练习,你为什么不用递归来写呢?”就是这样:

String.prototype.reverse = function() {
if (this.length <= 1) return this;
else return this.slice(1).reverse() + this.slice(0,1);
}

测试运行:

var s = "";
for(var i = 0; i < 1000; i++) {
s += ("apple" + i);
}
console.log(s.reverse());

输出:

999elppa899elppa...2elppa1elppa0elppa

尝试得到一个堆栈溢出,我改变100010000在谷歌Chrome浏览器,它报告:

RangeError: Maximum call stack size exceeded

我知道这是一个已经被很好地回答过的老问题,但为了自娱自乐,我写了下面的反向函数,并想把它分享给其他人,以防它对其他人有用。它处理代理对和组合标记:

function StringReverse (str)
{
var charArray = [];
for (var i = 0; i < str.length; i++)
{
if (i+1 < str.length)
{
var value = str.charCodeAt(i);
var nextValue = str.charCodeAt(i+1);
if (   (   value >= 0xD800 && value <= 0xDBFF
&& (nextValue & 0xFC00) == 0xDC00) // Surrogate pair)
|| (nextValue >= 0x0300 && nextValue <= 0x036F)) // Combining marks
{
charArray.unshift(str.substring(i, i+2));
i++; // Skip the other half
continue;
}
}


// Otherwise we just have a rogue surrogate marker or a plain old character.
charArray.unshift(str[i]);
}


return charArray.join('');
}

感谢Mathias、Punycode和其他各种参考资料,让我了解了JavaScript字符编码的复杂性。

没有将字符串转换为数组;

String.prototype.reverse = function() {


var ret = "";
var size = 0;


for (var i = this.length - 1; -1 < i; i -= size) {


if (
'\uD800' <= this[i - 1] && this[i - 1] <= '\uDBFF' &&
'\uDC00' <= this[i]     && this[i]     <= '\uDFFF'
) {
size = 2;
ret += this[i - 1] + this[i];
} else {
size = 1;
ret += this[i];
}
}


return ret;
}


console.log('anãnam anañam' === 'mañana mañana'.reverse());

使用数组。反向而不将字符转换为代码点;

String.prototype.reverse = function() {


var array = this.split("").reverse();


for (var i = 0; i < this.length; ++i) {


if (
'\uD800' <= this[i - 1] && this[i - 1] <= '\uDBFF' &&
'\uDC00' <= this[i]     && this[i]     <= '\uDFFF'
) {
array[i - 1] = array[i - 1] + array[i];
array[i] = array[i - 1].substr(0, 1);
array[i - 1] = array[i - 1].substr(1, 1);
}


}


return array.join("");
}


console.log('anãnam anañam' === 'mañana mañana'.reverse());
我认为String.prototype.reverse是解决这个问题的好方法;

.代码如下所示
String.prototype.reverse = function() {
return this.split('').reverse().join('');
}


var str = 'this is a good example for string reverse';
str.reverse();
-> "esrever gnirts rof elpmaxe doog a si siht";
function reverse(str){
var s = "";
for (var i = str.length - 1; i >= 0; i--){
s += str[i];
}
return s;
};
reverse("your string comes here")

下面的内容可能会帮助任何希望递归反转字符串的人。在最近的一次面试中,我被要求使用函数式编程风格:

var reverseStr = function(str) {
return (str.length > 0) ? str[str.length - 1] + reverseStr(str.substr(0, str.length -   1)) : '';
};


//tests
console.log(reverseStr('setab retsam')); //master bates

使用Array函数,

String.prototype.reverse = function(){
return [].reduceRight.call(this, function(last, secLast){return last + secLast});
}

详细分析和十种不同的方法来反转字符串和他们的性能细节。

http://eddmann.com/posts/ten-ways-to-reverse-a-string-in-javascript/

这些实现的性能:

每个浏览器的最佳执行实现

  • Chrome 15 -实现1和6
  • Firefox 7 -实现6
  • IE 9 -实现4
  • Opera 12 -实现9

以下是这些实现:

实现1:

function reverse(s) {
var o = '';
for (var i = s.length - 1; i >= 0; i--)
o += s[i];
return o;
}

实现2:

function reverse(s) {
var o = [];
for (var i = s.length - 1, j = 0; i >= 0; i--, j++)
o[j] = s[i];
return o.join('');
}

实现3:

function reverse(s) {
var o = [];
for (var i = 0, len = s.length; i <= len; i++)
o.push(s.charAt(len - i));
return o.join('');
}

实现4:

function reverse(s) {
return s.split('').reverse().join('');
}

实现5:

function reverse(s) {
var i = s.length,
o = '';
while (i > 0) {
o += s.substring(i - 1, i);
i--;
}
return o;
}

实现6:

function reverse(s) {
for (var i = s.length - 1, o = ''; i >= 0; o += s[i--]) { }
return o;
}

实现7:

function reverse(s) {
return (s === '') ? '' : reverse(s.substr(1)) + s.charAt(0);
}

实现8:

function reverse(s) {
function rev(s, len, o) {
return (len === 0) ? o : rev(s, --len, (o += s[len]));
};
return rev(s, s.length, '');
}

实现9:

function reverse(s) {
s = s.split('');
var len = s.length,
halfIndex = Math.floor(len / 2) - 1,
tmp;
 



for (var i = 0; i <= halfIndex; i++) {
tmp = s[len - i - 1];
s[len - i - 1] = s[i];
s[i] = tmp;
}
return s.join('');
}

实现10

function reverse(s) {
if (s.length < 2)
return s;
var halfIndex = Math.ceil(s.length / 2);
return reverse(s.substr(halfIndex)) +
reverse(s.substr(0, halfIndex));
}

实现11

var reverser  = function(str){
let string = str.split('');


for(i=0;i<string.length;i++){
debugger;
string.splice(i,0,string.pop());
    

}
console.log(string.join())
}
reverser('abcdef')

在一次面试中,我被要求在不使用任何变量或本机方法的情况下反转一个字符串。这是我最喜欢的实现:

function reverseString(str) {
return str === '' ? '' : reverseString(str.slice(1)) + str[0];
}
var str = "my name is saurabh ";
var empStr='',finalString='';
var chunk=[];
function reverse(str){
var i,j=0,n=str.length;
for(i=0;i<n;++i){
if(str[i]===' '){
chunk[j]=empStr;
empStr = '';
j++;
}else{
empStr=empStr+str[i];
}
}
for(var z=chunk.length-1;z>=0;z--){
finalString = finalString +' '+ chunk[z];
console.log(finalString);
}
return true;
}
reverse(str);

下面是一个基本的ES6不可变的例子,没有使用Array.prototype.reverse:

// :: reverse = String -> String
const reverse = s => [].reduceRight.call(s, (a, b) => a + b)


console.log(reverse('foo')) // => 'oof'
console.log(reverse('bar')) // => 'rab'
console.log(reverse('foo-bar')) // => 'rab-oof'

JavaScript中反转字符串的最佳方法

1) Array.reverse:

你可能会想,等等,我以为我们是反转字符串,为什么要用数组。逆向法。使用字符串。split方法中,我们将字符串转换为字符数组。然后反转数组中每个值的顺序,最后使用array将array转换回String。连接方法。

function reverseString(str) {
return str.split('').reverse().join('');
}
reverseString('dwayne');

2)递减while-loop:

尽管相当冗长,但这个解决方案确实比解决方案一有优势。你不是在创建一个数组,你只是根据源字符串中的字符连接一个字符串。

从性能的角度来看,这个方法可能会产生最好的结果(尽管未经测试)。但是对于非常长的字符串,性能增益可能会消失。

function reverseString(str) {
var temp = '';
var i = str.length;


while (i > 0) {
temp += str.substring(i - 1, i);
i--;
}




return temp;
}
reverseString('dwayne');

3)递归

我喜欢这个简单明了的解决方案。你可以清楚地看到字符串。charAt和String。Substr方法被用于通过每次调用自身来传递不同的值,直到字符串为空,而三元函数只会返回一个空字符串,而不是使用递归调用自身。这可能会产生第二个解决方案之后的第二优性能。

function reverseString(str) {
return (str === '') ? '' : reverseString(str.substr(1)) + str.charAt(0);
}
reverseString('dwayne');
var str = 'sample string';
[].map.call(str, function(x) {
return x;
}).reverse().join('');

var str = 'sample string';
console.log(str.split('').reverse().join(''));

//输出:'gnirts elpmas'

添加到String原型是理想的(只是以防它被添加到核心JS语言中),但你首先需要检查它是否存在,如果不存在就添加它,如下所示:

String.prototype.reverse = String.prototype.reverse || function () {
return this.split('').reverse().join('');
};

我想,这对你有用

function reverse(str){
str = str.split("").reverse().join("").split(" ").reverse().join(" ");
console.log(str)
}

我自己最初的尝试…

var str = "The Car";


function reverseStr(str) {
var reversed = "";
var len = str.length;
for (var i = 1; i < (len + 1); i++) {
reversed += str[len - i];
}


return reversed;
}


var strReverse = reverseStr(str);
console.log(strReverse);
// "raC ehT"

http://jsbin.com/bujiwo/19/edit?js,console,output

在ECMAScript 6中,你可以在不使用.split('')拆分方法的情况下更快地反转字符串,使用传播算子如下所示:

var str = [...'racecar'].reverse().join('');

反转字符串< em >, < / em >是不可能的,但是可以在不合适的位置执行。

首先,使用Array.from()将字符串转换为数组,然后使用Array.prototype.reverse()反转数组,然后使用Array.prototype.join()将其转换为字符串。

const reverse = str => Array.from(str).reverse().join('');

字符串本身是不可变的,但是你可以用下面的代码轻松地创建一个反向副本:

function reverseString(str) {


var strArray = str.split("");
strArray.reverse();


var strReverse = strArray.join("");


return strReverse;
}


reverseString("hello");

UTF-8字符串可以有:

  • 组合变音符,例如由b字符组成的和由unicode转义序列\u0303生成的~变音符;
  • 多字节字符,如🎥;它由多字节unicode转义序列\uD83C\uDFA5生成;而且
  • 多个字符可以用零宽度连接字符组合在一起(由unicode转义序列\u200D给出)。例如,字符👨‍👩‍👦可以使用单独的(多字节)表情符号👨,然后是一个零宽度的joiner,然后是👩,然后是另一个零宽度的joiner,然后是👦,这样整个3人字符是8字节(\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC66)。

这将处理反转所有3种情况,并保持字节在正确的顺序,以便反转字符(而不是天真地反转字符串的字节):

(function(){
var isCombiningDiacritic = function( code )
{
return (0x0300 <= code && code <= 0x036F)  // Comb. Diacritical Marks
|| (0x1AB0 <= code && code <= 0x1AFF)  // Comb. Diacritical Marks Extended
|| (0x1DC0 <= code && code <= 0x1DFF)  // Comb. Diacritical Marks Supplement
|| (0x20D0 <= code && code <= 0x20FF)  // Comb. Diacritical Marks for Symbols
|| (0xFE20 <= code && code <= 0xFE2F); // Comb. Half Marks


};


String.prototype.reverse = function()
{
let output = "";


for ( let i = this.length; i > 0; )
{
let width = 0;
let has_zero_width_joiner = false;


while( i > 0 && isCombiningDiacritic( this.charCodeAt(i-1) ) )
{
--i;
width++;
}


do {
--i;
width++;


if (
i > 0
&& "\uDC00" <= this[i]   && this[i]   <= "\uDFFF"
&& "\uD800" <= this[i-1] && this[i-1] <= "\uDBFF"
)
{
--i;
width++;
}
has_zero_width_joiner = i > 0 && "\u200D" == this[i-1];
if ( has_zero_width_joiner )
{
--i;
width++;
}
}
while( i > 0 && has_zero_width_joiner );


output += this.substr( i, width );
}


return output;
}
})();


// Tests
[
'abcdefg',
'ab\u0303c',
'a\uD83C\uDFA5b',
'a\uD83C\uDFA5b\uD83C\uDFA6c',
'a\uD83C\uDFA5b\u0306c\uD83C\uDFA6d',
'TO͇̹̺ͅƝ̴ȳ̳ TH̘Ë͖́̉ ͠P̯͍̭O̚​N̐Y̡', // copied from http://stackoverflow.com/a/1732454/1509264
'What 👨‍👩‍👦 is this?'
].forEach(
function(str){ console.log( str + " -> " + str.reverse() ); }
);

更新

上面的代码标识了一些比较常用的组合变音符号。一个更完整的组合变音符的列表(可以交换到上面的代码中)是:

var isCombiningDiacritic = function( code )
{
return (0x0300 <= code && code <= 0x036F)
|| (0x0483 <= code && code <= 0x0489)
|| (0x0591 <= code && code <= 0x05BD)
|| (code == 0x05BF)
|| (0x05C1 <= code && code <= 0x05C2)
|| (0x05C4 <= code && code <= 0x05C5)
|| (code == 0x05C7)
|| (0x0610 <= code && code <= 0x061A)
|| (0x064B <= code && code <= 0x065F)
|| (code == 0x0670)
|| (0x06D6 <= code && code <= 0x06DC)
|| (0x06DF <= code && code <= 0x06E4)
|| (0x06E7 <= code && code <= 0x06E8)
|| (0x06EA <= code && code <= 0x06ED)
|| (code == 0x0711)
|| (0x0730 <= code && code <= 0x074A)
|| (0x07A6 <= code && code <= 0x07B0)
|| (0x07EB <= code && code <= 0x07F3)
|| (code == 0x07FD)
|| (0x0816 <= code && code <= 0x0819)
|| (0x081B <= code && code <= 0x0823)
|| (0x0825 <= code && code <= 0x0827)
|| (0x0829 <= code && code <= 0x082D)
|| (0x0859 <= code && code <= 0x085B)
|| (0x08D3 <= code && code <= 0x08E1)
|| (0x08E3 <= code && code <= 0x0902)
|| (code == 0x093A)
|| (code == 0x093C)
|| (0x0941 <= code && code <= 0x0948)
|| (code == 0x094D)
|| (0x0951 <= code && code <= 0x0957)
|| (0x0962 <= code && code <= 0x0963)
|| (code == 0x0981)
|| (code == 0x09BC)
|| (0x09C1 <= code && code <= 0x09C4)
|| (code == 0x09CD)
|| (0x09E2 <= code && code <= 0x09E3)
|| (0x09FE <= code && code <= 0x0A02)
|| (code == 0x0A3C)
|| (0x0A41 <= code && code <= 0x0A51)
|| (0x0A70 <= code && code <= 0x0A71)
|| (code == 0x0A75)
|| (0x0A81 <= code && code <= 0x0A82)
|| (code == 0x0ABC)
|| (0x0AC1 <= code && code <= 0x0AC8)
|| (code == 0x0ACD)
|| (0x0AE2 <= code && code <= 0x0AE3)
|| (0x0AFA <= code && code <= 0x0B01)
|| (code == 0x0B3C)
|| (code == 0x0B3F)
|| (0x0B41 <= code && code <= 0x0B44)
|| (0x0B4D <= code && code <= 0x0B56)
|| (0x0B62 <= code && code <= 0x0B63)
|| (code == 0x0B82)
|| (code == 0x0BC0)
|| (code == 0x0BCD)
|| (code == 0x0C00)
|| (code == 0x0C04)
|| (0x0C3E <= code && code <= 0x0C40)
|| (0x0C46 <= code && code <= 0x0C56)
|| (0x0C62 <= code && code <= 0x0C63)
|| (code == 0x0C81)
|| (code == 0x0CBC)
|| (0x0CCC <= code && code <= 0x0CCD)
|| (0x0CE2 <= code && code <= 0x0CE3)
|| (0x0D00 <= code && code <= 0x0D01)
|| (0x0D3B <= code && code <= 0x0D3C)
|| (0x0D41 <= code && code <= 0x0D44)
|| (code == 0x0D4D)
|| (0x0D62 <= code && code <= 0x0D63)
|| (code == 0x0DCA)
|| (0x0DD2 <= code && code <= 0x0DD6)
|| (code == 0x0E31)
|| (0x0E34 <= code && code <= 0x0E3A)
|| (0x0E47 <= code && code <= 0x0E4E)
|| (code == 0x0EB1)
|| (0x0EB4 <= code && code <= 0x0EBC)
|| (0x0EC8 <= code && code <= 0x0ECD)
|| (0x0F18 <= code && code <= 0x0F19)
|| (code == 0x0F35)
|| (code == 0x0F37)
|| (code == 0x0F39)
|| (0x0F71 <= code && code <= 0x0F7E)
|| (0x0F80 <= code && code <= 0x0F84)
|| (0x0F86 <= code && code <= 0x0F87)
|| (0x0F8D <= code && code <= 0x0FBC)
|| (code == 0x0FC6)
|| (0x102D <= code && code <= 0x1030)
|| (0x1032 <= code && code <= 0x1037)
|| (0x1039 <= code && code <= 0x103A)
|| (0x103D <= code && code <= 0x103E)
|| (0x1058 <= code && code <= 0x1059)
|| (0x105E <= code && code <= 0x1060)
|| (0x1071 <= code && code <= 0x1074)
|| (code == 0x1082)
|| (0x1085 <= code && code <= 0x1086)
|| (code == 0x108D)
|| (code == 0x109D)
|| (0x135D <= code && code <= 0x135F)
|| (0x1712 <= code && code <= 0x1714)
|| (0x1732 <= code && code <= 0x1734)
|| (0x1752 <= code && code <= 0x1753)
|| (0x1772 <= code && code <= 0x1773)
|| (0x17B4 <= code && code <= 0x17B5)
|| (0x17B7 <= code && code <= 0x17BD)
|| (code == 0x17C6)
|| (0x17C9 <= code && code <= 0x17D3)
|| (code == 0x17DD)
|| (0x180B <= code && code <= 0x180D)
|| (0x1885 <= code && code <= 0x1886)
|| (code == 0x18A9)
|| (0x1920 <= code && code <= 0x1922)
|| (0x1927 <= code && code <= 0x1928)
|| (code == 0x1932)
|| (0x1939 <= code && code <= 0x193B)
|| (0x1A17 <= code && code <= 0x1A18)
|| (code == 0x1A1B)
|| (code == 0x1A56)
|| (0x1A58 <= code && code <= 0x1A60)
|| (code == 0x1A62)
|| (0x1A65 <= code && code <= 0x1A6C)
|| (0x1A73 <= code && code <= 0x1A7F)
|| (0x1AB0 <= code && code <= 0x1B03)
|| (code == 0x1B34)
|| (0x1B36 <= code && code <= 0x1B3A)
|| (code == 0x1B3C)
|| (code == 0x1B42)
|| (0x1B6B <= code && code <= 0x1B73)
|| (0x1B80 <= code && code <= 0x1B81)
|| (0x1BA2 <= code && code <= 0x1BA5)
|| (0x1BA8 <= code && code <= 0x1BA9)
|| (0x1BAB <= code && code <= 0x1BAD)
|| (code == 0x1BE6)
|| (0x1BE8 <= code && code <= 0x1BE9)
|| (code == 0x1BED)
|| (0x1BEF <= code && code <= 0x1BF1)
|| (0x1C2C <= code && code <= 0x1C33)
|| (0x1C36 <= code && code <= 0x1C37)
|| (0x1CD0 <= code && code <= 0x1CD2)
|| (0x1CD4 <= code && code <= 0x1CE0)
|| (0x1CE2 <= code && code <= 0x1CE8)
|| (code == 0x1CED)
|| (code == 0x1CF4)
|| (0x1CF8 <= code && code <= 0x1CF9)
|| (0x1DC0 <= code && code <= 0x1DFF)
|| (0x20D0 <= code && code <= 0x20F0)
|| (0x2CEF <= code && code <= 0x2CF1)
|| (code == 0x2D7F)
|| (0x2DE0 <= code && code <= 0x2DFF)
|| (0x302A <= code && code <= 0x302D)
|| (0x3099 <= code && code <= 0x309A)
|| (0xA66F <= code && code <= 0xA672)
|| (0xA674 <= code && code <= 0xA67D)
|| (0xA69E <= code && code <= 0xA69F)
|| (0xA6F0 <= code && code <= 0xA6F1)
|| (code == 0xA802)
|| (code == 0xA806)
|| (code == 0xA80B)
|| (0xA825 <= code && code <= 0xA826)
|| (0xA8C4 <= code && code <= 0xA8C5)
|| (0xA8E0 <= code && code <= 0xA8F1)
|| (code == 0xA8FF)
|| (0xA926 <= code && code <= 0xA92D)
|| (0xA947 <= code && code <= 0xA951)
|| (0xA980 <= code && code <= 0xA982)
|| (code == 0xA9B3)
|| (0xA9B6 <= code && code <= 0xA9B9)
|| (0xA9BC <= code && code <= 0xA9BD)
|| (code == 0xA9E5)
|| (0xAA29 <= code && code <= 0xAA2E)
|| (0xAA31 <= code && code <= 0xAA32)
|| (0xAA35 <= code && code <= 0xAA36)
|| (code == 0xAA43)
|| (code == 0xAA4C)
|| (code == 0xAA7C)
|| (code == 0xAAB0)
|| (0xAAB2 <= code && code <= 0xAAB4)
|| (0xAAB7 <= code && code <= 0xAAB8)
|| (0xAABE <= code && code <= 0xAABF)
|| (code == 0xAAC1)
|| (0xAAEC <= code && code <= 0xAAED)
|| (code == 0xAAF6)
|| (code == 0xABE5)
|| (code == 0xABE8)
|| (code == 0xABED)
|| (code == 0xFB1E)
|| (0xFE00 <= code && code <= 0xFE0F)
|| (0xFE20 <= code && code <= 0xFE2F)
|| (code == 0x101FD)
|| (code == 0x102E0)
|| (0x10376 <= code && code <= 0x1037A)
|| (0x10A01 <= code && code <= 0x10A0F)
|| (0x10A38 <= code && code <= 0x10A3F)
|| (0x10AE5 <= code && code <= 0x10AE6)
|| (0x10D24 <= code && code <= 0x10D27)
|| (0x10F46 <= code && code <= 0x10F50)
|| (code == 0x11001)
|| (0x11038 <= code && code <= 0x11046)
|| (0x1107F <= code && code <= 0x11081)
|| (0x110B3 <= code && code <= 0x110B6)
|| (0x110B9 <= code && code <= 0x110BA)
|| (0x11100 <= code && code <= 0x11102)
|| (0x11127 <= code && code <= 0x1112B)
|| (0x1112D <= code && code <= 0x11134)
|| (code == 0x11173)
|| (0x11180 <= code && code <= 0x11181)
|| (0x111B6 <= code && code <= 0x111BE)
|| (0x111C9 <= code && code <= 0x111CC)
|| (0x1122F <= code && code <= 0x11231)
|| (code == 0x11234)
|| (0x11236 <= code && code <= 0x11237)
|| (code == 0x1123E)
|| (code == 0x112DF)
|| (0x112E3 <= code && code <= 0x112EA)
|| (0x11300 <= code && code <= 0x11301)
|| (0x1133B <= code && code <= 0x1133C)
|| (code == 0x11340)
|| (0x11366 <= code && code <= 0x11374)
|| (0x11438 <= code && code <= 0x1143F)
|| (0x11442 <= code && code <= 0x11444)
|| (code == 0x11446)
|| (code == 0x1145E)
|| (0x114B3 <= code && code <= 0x114B8)
|| (code == 0x114BA)
|| (0x114BF <= code && code <= 0x114C0)
|| (0x114C2 <= code && code <= 0x114C3)
|| (0x115B2 <= code && code <= 0x115B5)
|| (0x115BC <= code && code <= 0x115BD)
|| (0x115BF <= code && code <= 0x115C0)
|| (0x115DC <= code && code <= 0x115DD)
|| (0x11633 <= code && code <= 0x1163A)
|| (code == 0x1163D)
|| (0x1163F <= code && code <= 0x11640)
|| (code == 0x116AB)
|| (code == 0x116AD)
|| (0x116B0 <= code && code <= 0x116B5)
|| (code == 0x116B7)
|| (0x1171D <= code && code <= 0x1171F)
|| (0x11722 <= code && code <= 0x11725)
|| (0x11727 <= code && code <= 0x1172B)
|| (0x1182F <= code && code <= 0x11837)
|| (0x11839 <= code && code <= 0x1183A)
|| (0x119D4 <= code && code <= 0x119DB)
|| (code == 0x119E0)
|| (0x11A01 <= code && code <= 0x11A06)
|| (0x11A09 <= code && code <= 0x11A0A)
|| (0x11A33 <= code && code <= 0x11A38)
|| (0x11A3B <= code && code <= 0x11A3E)
|| (code == 0x11A47)
|| (0x11A51 <= code && code <= 0x11A56)
|| (0x11A59 <= code && code <= 0x11A5B)
|| (0x11A8A <= code && code <= 0x11A96)
|| (0x11A98 <= code && code <= 0x11A99)
|| (0x11C30 <= code && code <= 0x11C3D)
|| (0x11C92 <= code && code <= 0x11CA7)
|| (0x11CAA <= code && code <= 0x11CB0)
|| (0x11CB2 <= code && code <= 0x11CB3)
|| (0x11CB5 <= code && code <= 0x11CB6)
|| (0x11D31 <= code && code <= 0x11D45)
|| (code == 0x11D47)
|| (0x11D90 <= code && code <= 0x11D91)
|| (code == 0x11D95)
|| (code == 0x11D97)
|| (0x11EF3 <= code && code <= 0x11EF4)
|| (0x16AF0 <= code && code <= 0x16AF4)
|| (0x16B30 <= code && code <= 0x16B36)
|| (code == 0x16F4F)
|| (0x16F8F <= code && code <= 0x16F92)
|| (0x1BC9D <= code && code <= 0x1BC9E)
|| (0x1D167 <= code && code <= 0x1D169)
|| (0x1D17B <= code && code <= 0x1D182)
|| (0x1D185 <= code && code <= 0x1D18B)
|| (0x1D1AA <= code && code <= 0x1D1AD)
|| (0x1D242 <= code && code <= 0x1D244)
|| (0x1DA00 <= code && code <= 0x1DA36)
|| (0x1DA3B <= code && code <= 0x1DA6C)
|| (code == 0x1DA75)
|| (code == 0x1DA84)
|| (0x1DA9B <= code && code <= 0x1E02A)
|| (0x1E130 <= code && code <= 0x1E136)
|| (0x1E2EC <= code && code <= 0x1E2EF)
|| (0x1E8D0 <= code && code <= 0x1E8D6)
|| (0x1E944 <= code && code <= 0x1E94A)
|| (0xE0100 <= code && code <= 0xE01EF);
};
//es6
//array.from
const reverseString = (string) => Array.from(string).reduce((a, e) => e + a);
//split
const reverseString = (string) => string.split('').reduce((a, e) => e + a);


//split problem
"𠜎𠺢".split('')[0] === Array.from("𠜎𠺢")[0] // "�" === "𠜎" => false
"😂😹🤗".split('')[0] === Array.from("😂😹🤗")[0] // "�" === "😂" => false

这样的事情应该遵循最佳实践:

(function(){
'use strict';
var str = "testing";
	

//using array methods
var arr = new Array();
arr = str.split("");
arr.reverse();
console.log(arr);
	

//using custom methods
var reverseString = function(str){
		

if(str == null || str == undefined || str.length == 0 ){
return "";
}
		

if(str.length == 1){
return str;
}
		

var rev = [];
for(var i = 0; i < str.length; i++){
rev[i] = str[str.length - 1 - i];
}
return rev;
}
	

console.log(reverseString(str));
	

})();

保持干燥和简单,傻!!

function reverse(s){
let str = s;
var reverse = '';
for (var i=str.length;i>0;i--){


var newstr = str.substring(0,i)
reverse += newstr.substr(-1,1)
}
return reverse;
}

好吧,非常简单,你可以创建一个简单的循环函数来反向执行字符串,而不需要使用reverse()charAt()等,如下所示:

例如,你有这样一个字符串:

var name = "StackOverflow";

创建一个这样的函数,我把它命名为reverseString

function reverseString(str) {
if(!str.trim() || 'string' !== typeof str) {
return;
}
let l=str.length, s='';
while(l > 0) {
l--;
s+= str[l];
}
return s;
}

你可以这样称呼它:

reverseString(name);

结果是:

"wolfrevOkcatS"

如果你不想使用任何内置功能。试试这个

var string = 'abcdefg';
var newstring = '';


for(let i = 0; i < string.length; i++){
newstring = string[i] += newstring;
}


console.log(newstring);
var reverseString = function(str){
let length = str.length - 1;
str = str.split('');


for(let i=0;i<= length;i++){
str[length + i + 1] = str[length - i];
}


return str.splice(length + 1).join('');
}

在ES6中,你还有一个选择

function reverseString (str) {
return [...str].reverse().join('')
}


reverseString('Hello');

有多种方法,你可以检查下面的,

1. 传统的for循环(递增):

function reverseString(str){
let stringRev ="";
for(let i= 0; i<str.length; i++){
stringRev = str[i]+stringRev;
}
return stringRev;
}
alert(reverseString("Hello World!"));

2. 传统的for循环(递减):

function reverseString(str){
let revstr = "";
for(let i = str.length-1; i>=0; i--){
revstr = revstr+ str[i];
}
return revstr;
}
alert(reverseString("Hello World!"));

3.使用for-of循环

function reverseString(str){
let strn ="";
for(let char of str){
strn = char + strn;
}
return strn;
}
alert(reverseString("Get well soon"));

4. 使用forEach/高阶数组方法:

function reverseString(str){


let revSrring = "";
str.split("").forEach(function(char){
    

revSrring = char + revSrring;
  

});
return revSrring;
}
alert(reverseString("Learning JavaScript"));

5. ES6标准:

function reverseString(str){


let revSrring = "";
str.split("").forEach(char => revSrring = char + revSrring);
return revSrring;
}
alert(reverseString("Learning JavaScript"));

6. 最新的方式:

function reverseString(str){


return str.split("").reduce(function(revString, char){
return char + revString;
}, "");
 

}


alert(reverseString("Learning JavaScript"));

7. 你也可以用下面的方法得到结果,

function reverseString(str){


return str.split("").reduce((revString, char)=> char + revString, "");
 

}
alert(reverseString("Learning JavaScript"));

以下是可以用来实现字符串反转的四种最常用方法

给定一个字符串,返回一个颠倒的新字符串 字符顺序

问题的多种解决方案

//reverse('apple') === 'leppa'
//reverse('hello') === 'olleh'
//reverse('Greetings!') === '!sgniteerG'


// 1. First method without using reverse function and negative for loop
function reverseFirst(str) {
if(str !== '' || str !==undefined || str !== null) {
const reversedStr = [];
for(var i=str.length; i>-1; i--) {
reversedStr.push(str[i]);
}
return reversedStr.join("").toString();
}
}


// 2. Second method using the reverse function
function reverseSecond(str) {
return str.split('').reverse().join('');
}


// 3. Third method using the positive for loop
function reverseThird(str){
const reversedStr = [];
for(i=0; i<str.length;i++) {
reversedStr.push(str[str.length-1-i])
}
return reversedStr.join('').toString();
}


// 4. using the modified for loop ES6
function reverseForth(str) {
const reversedStr = [];
for(let character of str) {
reversedStr = character + reversedStr;
}
return reversedStr;
}


// 5. Using Reduce function
function reverse(str) {
return str.split('').reduce((reversed, character) => {
return character + reversed;
}, '');
}
word.split('').reduce((acc, curr) => curr+""+acc)

在JavaScript中有许多方法可以反转字符串。我正在记下我喜欢的三种方法。

方法一:使用反向函数:

function reverse(str) {
return str.split('').reverse().join('');
}

方法2:循环字符:

function reverse(str) {
let reversed = '';


for (let character of str) {
reversed = character + reversed;
}


return reversed;
}

方法3:使用reduce函数:

function reverse(str) {
return str.split('').reduce((rev, char) => char + rev, '');
}

我希望这对你有所帮助:)

你不能,因为JS字符串是不可变的。短的非就地解决方案

[...str].reverse().join``

let str = "Hello World!";
let r = [...str].reverse().join``;
console.log(r);

没有内置方法?鉴于Javascript中的字符串是不可变的,您可能希望使用内置的方法,如split、join等。但这里有两种不使用这些方法的方法:

function ReverseString(str) {
var len = str.length;
var newString = [];


while (len--) {
newString.push(str[len]);
}


return newString.join('');
}


console.log(ReverseString('amgod')) //dogma


function RecursiveStringReverse(str, len) {
if (len === undefined)
len = str.length - 1;


if (len > 0)
return str[len] + RecursiveReverse(str, --len);


return str[len];
}


console.log(RecursiveStringReverse('Hello, world!'))// !dlrow ,olleH

使用内置函数反转字符串

function reverse(str) {
// Use the split() method to return a new array
//  Use the reverse() method to reverse the new created array
// Use the join() method to join all elements of the array into a string
return str.split("").reverse().join("");
}
console.log(reverse('hello'));


反转一个没有helper的字符串

function reversedOf(str) {
let newStr = '';
for (let char of str) {
newStr = char + newStr
// 1st round: "h" + "" = h, 2nd round: "e" + "h" = "eh" ... etc.
// console.log(newStr);
}
return newStr;
}
console.log(reversedOf('hello'));

添加的反向字符串没有循环,它是通过递归工作。

function reverse(y){
if(y.length==1 || y.length == 0 ){
return y;
}
return y.split('')[y.length - 1]+ reverse(y.slice(0, y.length-1));
}
console.log(reverse("Hello"));

一个新的选项是使用Intl。裂殖体,它允许你在可视字母上进行分割(例如:用户感知的字符单位,如表情符号、字符等)。Intl.Segmenter目前是第四阶段提案,如果你想使用它,有一个polyfill可用。它目前有有限的浏览器支持,你可以找到更多关于在这里的信息。

如果你使用Intl.Segmenter,下面是reverse()方法的样子:

const reverse = str => {
const segmenter = new Intl.Segmenter("en", {granularity: 'grapheme'});
const segitr = segmenter.segment(str);
const segarr = Array.from(segitr, ({segment}) => segment).reverse();
return segarr.join('');
}


console.log(reverse('foo 𝌆 bar mañana mañana')); // anañam anañam rab 𝌆 oof
console.log(reverse('This 😊 emoji is happy')); // yppah si ijome 😊 sihT
console.log(reverse('Text surrogate pair 𝌆 composite pair möo varient selector ❤️ & ZWJ 👨‍👩‍👦')); // 👨‍👩‍👦 JWZ & ❤️ rotceles tneirav oöm riap etisopmoc 𝌆 riap etagorrus txeT

上面创建了一个segmenter来根据可视字母来分割字符串。使用字符串输入在segmenter上调用.segment(),然后返回一个迭代器,该迭代器生成形式为{segment, index, input, isWordLike}的对象。该对象的segment键包含字符串段(即:单个字素)。为了将迭代器转换为数组,我们在迭代器上使用Array.from()并提取分段的字母,可以使用.reverse()反转。最后,我们使用.join()将数组连接回字符串


还有另一个选项,你可以尝试有更好的浏览器支持比Intl。然而,分割器并不是那么防弹:

const reverse = str => Array.from(str.normalize('NFC')).reverse().join('');

这有助于处理由多个代码点和代码单元组成的字符。正如在其他回答中指出的,在'foo 𝌆 bar mañana mañana'这样的字符串中维护复合和代理对排序存在问题。这里𝌆是由两个代码单元组成的代理对,而最后一个是由两个Unicode字符组成一个字素的组合对(n+̃ = )。

为了反转每个字符,你可以使用.reverse()方法,它是数组原型的一部分。当.reverse()用于数组时,要做的第一件事是将字符串转换为字符数组。通常情况下,.split('')用于此任务,然而,这将拆分由多个代码单元组成的代理对(如之前的答案所示):

>> '𝌆'.split('')
>> `["�", "�"]`

相反,如果你调用String.prototypeSymbol.iterator方法,那么你将能够在数组中保留你的代理对,因为这是在代码点而不是字符串的代码单元上迭代:

>> [...'𝌆']
>> ["𝌆"]

接下来要处理的是字符串中的任何复合字符。由两个或多个代码点组成的字符在迭代时仍然会被分割:

>> [...'ö']
>> ["o", "̈"]

上述内容将基本字符(o)与透析分离开来,这不是理想的行为。这是因为是字符的分解版本,由多个代码点组成。要处理这个问题,可以使用ES6中引入的字符串方法String.prototype.normalize()。该方法可以使用&;NFC"将多个代码点组合到组合标准形中;作为一个论证。这允许我们将已分解的字符 (o + 结合分音符)转换为仅由一个码位组成的预组合形式ö (拉丁文小字母o,带有diaeresis)。因此,使用"NFC"调用.normalize()试图用单个代码点String.prototype.normalize()0替换多个代码点。这使得由两个码位组成的字素可以用一个码位表示。

>> [...'ö'.normalize('NFC')]
>> ["ö"]

normalize('NFC')生成一个字符时,它可以安全地在其他字符之间被反转。将扩展语法和规范化放在一起,你可以成功地反转字符串,例如:

const reverse = str => Array.from(str.normalize('NFC')).reverse().join('');


console.log(reverse('foo 𝌆 bar mañana mañana'));
console.log(reverse('This 😊 emoji is happy'));

在少数情况下,上述归一化+迭代会失败。例如,字符❤️(沉重的黑心❤️)由两个代码点组成。第一个是心形,后者是变异selector-16 (U+FE0F),用于为前一个字符定义字形变体。其他角色也会产生类似的问题。

另一件需要注意的事情是ZWJ(零宽细木工)字符,您可以在一些脚本中找到它们,包括表情符号。例如,表情符号👨‍👩‍👦由男人、女人和男孩的表情符号组成,每个表情符号由一个ZWJ隔开。上述归一化+迭代的方法也不能解释这一点。

因此,使用Intl.Segmenter是这两种方法中更好的选择。目前,Chrome也有自己的细分API称为Intl.v8BreakIterator。这个分割API是# eyz2标准的,Chrome只是实现了一些东西。因此,它可能会发生变化,并且不能在大多数浏览器上运行,因此不建议使用。然而,如果你好奇,这是可以做到的:

const reverse = str => {
const iterator = Intl.v8BreakIterator(['en'], {type: 'character'});
iterator.adoptText(str);
const arr = [];
let pos = iterator.first();
while (pos !== -1) {
const current = iterator.current();
const nextPos = iterator.next();
if (nextPos === -1) break;
const slice = str.slice(current, nextPos);
arr.unshift(slice);
}
return arr.join("");
}


console.log(reverse('foo 𝌆 bar mañana mañana')); // anañam anañam rab 𝌆 oof
console.log(reverse('This 😊 emoji is happy')); // yppah si ijome 😊 sihT
console.log(reverse('Text surrogate pair 𝌆 composite pair möo varient selector ❤️ & ZWJ 👨‍👩‍👦')); // 👨‍👩‍👦 JWZ & ❤️ rotceles tneirav oöm riap etisopmoc 𝌆 riap etagorrus txeT

    function reverse(string)
{
let arr = [];
for(let char of string) {
arr.unshift(char);
}
let rev = arr.join('')
return rev
}
    

let result = reverse("hello")
console.log(result)

如果您对性能和时间复杂度更感兴趣,可以使用此方法。在这个方法中,我将字符串分为两部分,并按照长度/2次循环迭代进行排序。

let str = "abcdefghijklmnopqrstuvwxyz"


function reverse(str){
let store = ""
let store2 = ""


for(let i=str.length/2;i>=0;i--){
if(str.length%2!==0){
store += str.charAt(i)
store2 += str.slice((str.length/2)+1, str.length).charAt(i)
}else{
store += str.charAt(i-1)
store2 += str.slice((str.length/2), str.length).charAt(i)
}
  

}
return store2+store
}


console.log(reverse(str))

这不是最优的,但我们可以这样想。

使用扩展语法的清晰方式:

const reverseString = str => [...str].reverse().join('');


console.log(reverseString('ABC'));

我们可以从字符串数组的两端开始迭代:start和end,并在每次迭代中交换。

function reverse(str) {
let strArray = str.split("");
let start = 0;
let end = strArray.length - 1;


while(start <= end) {
let temp = strArray[start];
strArray[start] = strArray[end];
strArray[end] = temp;


start++;
end--;
}
return strArray.join("");
}

虽然操作次数减少了,但其时间复杂度仍为O(n) 操作的数量仍然与输入的大小成线性比例

裁判:# EYZ0

你不能反转string,但你可以使用这个:

String.prototype.reverse = function() {
return this.split("").reverse().join("");
}


var s = "ABCD";
s = s.reverse();
console.log(s);

其中一种方法也可以是在使用分割法后再使用还原法进行逆向。

function reverse(str) {
return str.split('').reduce((rev, currentChar) => currentChar + rev, '');
}
console.log(reverse('apple'));
console.log(reverse('hello'));
console.log(reverse('Greetings!'));

// try this simple way


const reverseStr = (str) => {
let newStr = "";
for (let i = str.length - 1; i >= 0; i--) {
newStr += str[i];
}
return newStr;
}
console.log(reverseStr("ABCDEFGH")); //HGFEDCBA
function reverseWords(str) {
// Go for it
const invertirPalabra = palabra => palabra.split('').reverse().join('')
return str.split(' ').map(invertirPalabra).join(' ')
// con split convierto string en array de palabras, le paso ' '
// que es que me lo separe por espacios
// luego invierto cada palabra...
// y luego con join las uno separando por espacios
}

ES6

 function reverseString(str) {
return [...str].reverse().join("");
}


console.log(reverseString("Hello")); // olleH
//recursive implementation
function reverse(wrd) {
const str =wrd[0]
if(!wrd.length) {
return wrd
}
return reverse(wrd.slice(1)) + str
}