Làm thế nào để bạn đảo ngược một chuỗi tại chỗ trong JavaScript?


434

Làm thế nào để bạn đảo ngược một chuỗi tại chỗ (hoặc tại chỗ) trong JavaScript khi nó được chuyển đến một hàm bằng câu lệnh return, mà không sử dụng các hàm dựng sẵn ( .reverse(), .charAt()v.v.)?


vì vậy, bạn không được phép sử dụng .charAt () để lấy các ký tự của chuỗi?
Irwin

155
Bạn không thể. Các chuỗi JavaScript là bất biến, có nghĩa là bộ nhớ được phân bổ cho từng chuỗi không thể được ghi vào, làm cho các đảo ngược "tại chỗ" thực sự là không thể.
Lưỡi liềm tươi

2
Re: bình luận của crescentfresh xem stackoverflow.com/questions/51185/ từ
baudtack

1
@crescentfresh bạn nên đăng nó như một câu trả lời mới.
baudtack

Câu trả lời:


736

Miễn là bạn đang xử lý các ký tự ASCII đơn giản và bạn vui lòng sử dụng các hàm tích hợp, điều này sẽ hoạt động:

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

Nếu bạn cần một giải pháp hỗ trợ UTF-16 hoặc các ký tự nhiều byte khác, hãy lưu ý rằng hàm này sẽ cung cấp các chuỗi unicode không hợp lệ hoặc các chuỗi hợp lệ trông buồn cười. Bạn có thể muốn xem xét câu trả lời này thay thế .

[... s] là nhận biết Unicode, một chỉnh sửa nhỏ mang lại: -

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

44
Điều này bị phá vỡ đối với các chuỗi UTF-16 có chứa các cặp thay thế, tức là các ký tự bên ngoài mặt phẳng đa ngôn ngữ cơ bản. Nó cũng sẽ cung cấp kết quả hài hước cho các chuỗi có chứa các ký tự kết hợp, ví dụ: một dấu gạch chéo có thể xuất hiện trên ký tự sau. Vấn đề đầu tiên sẽ dẫn đến các chuỗi unicode không hợp lệ, chuỗi thứ hai thành hợp lệ trông buồn cười.
Martin Probst

2
@Richeve Bebedor "Tất cả mà không sử dụng các hàm dựng sẵn? .Oreverse ()" Đây sẽ không phải là một giải pháp được chấp nhận vì nó không phù hợp trong giới hạn của câu hỏi, mặc dù là một giải pháp khả thi để đảo ngược chuỗi trong JS.
David Starkey

1
@DavidStarkey: Vâng, nhìn lại điều này gần bốn năm sau, thật khó để thấy tôi đã bỏ lỡ quan điểm của câu hỏi như thế nào. Có vẻ như tôi chỉ nên đợi hai phút và đưa ra nhận xét của crescentfresh về bài viết gốc!
belacqua

14
@MartinProbst Câu trả lời của tôi cung cấp giải pháp nhận biết Unicode cho vấn đề liên quan đến các cặp thay thế và kết hợp các dấu chính xác: stackoverflow.com/a/16776380/96656
Mathias Bynens

1
Đối với UTF-16 return [...s].reverse().join("");có thể hoạt động.
dùng4642212

410

Kỹ thuật sau (hoặc tương tự) thường được sử dụng để đảo ngược chuỗi trong JavaScript:

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

Trong thực tế, tất cả các câu trả lời được đăng cho đến nay là một biến thể của mẫu này. Tuy nhiên, có một số vấn đề với giải pháp này. Ví dụ:

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

Nếu bạn đang tự hỏi tại sao điều này xảy ra, hãy đọc mã hóa ký tự bên trong của JavaScript . (TL; DR: 𝌆là một biểu tượng vĩ đại và JavaScript hiển thị nó dưới dạng hai đơn vị mã riêng biệt.)

Nhưng còn nữa:

// 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.

Một chuỗi tốt để kiểm tra việc triển khai ngược chuỗi là như sau :

'foo 𝌆 bar mañana mañana'

Tại sao? Bởi vì nó chứa một biểu tượng Astral ( 𝌆) (được biểu thị bằng các cặp thay thế trong JavaScript ) và dấu kết hợp ( cuối cùng mañanathực sự bao gồm hai biểu tượng: U + 006E LATIN SMALL LETTER N và U + 0303 COMBINING TILDE).

Thứ tự xuất hiện các cặp thay thế xuất hiện không thể đảo ngược, nếu không thì biểu tượng thiên văn sẽ không xuất hiện nữa trong chuỗi 'đảo ngược'. Đó là lý do tại sao bạn thấy những ��dấu hiệu đó trong đầu ra cho ví dụ trước.

Các dấu kết hợp luôn được áp dụng cho biểu tượng trước đó, do đó, bạn phải coi cả biểu tượng chính (U + 006E LATIN SMALL LETTER N) là toàn bộ dấu kết hợp (U + 0303 COMBINING TILDE). Đảo ngược thứ tự của chúng sẽ làm cho dấu kết hợp được ghép với một biểu tượng khác trong chuỗi. Đó là lý do tại sao đầu ra ví dụ có thay vì ñ.

Hy vọng, điều này giải thích tại sao tất cả các câu trả lời được đăng cho đến nay là sai .


Để trả lời câu hỏi ban đầu của bạn - cách [đúng] đảo ngược một chuỗi trong JavaScript -, tôi đã viết một thư viện JavaScript nhỏ có khả năng đảo ngược chuỗi nhận biết Unicode. Nó không có bất kỳ vấn đề nào tôi vừa đề cập. Thư viện được gọi là Esrever ; mã của nó là trên GitHub và nó hoạt động trong hầu hết mọi môi trường JavaScript. Nó đi kèm với một tiện ích shell / nhị phân, vì vậy bạn có thể dễ dàng đảo ngược chuỗi từ thiết bị đầu cuối của bạn nếu bạn muốn.

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

Đối với phần của điểm tại chỗ, hãy xem các câu trả lời khác.


65
Bạn nên bao gồm phần chính của mã Esrever trong câu trả lời của bạn.
r0estir0bbe

1
@Meglio Với cách tiếp cận cụ thể đó, vâng.
Mathias Bynens

8
Vấn đề, tất nhiên, là "đảo ngược một chuỗi" nghe có vẻ không rõ ràng, nhưng nó không phải đối mặt với các vấn đề được đề cập ở đây. Là đảo ngược một chuỗi trả về chuỗi mà khi được in sẽ hiển thị các cụm grapheme trong chuỗi theo thứ tự ngược lại? Một mặt, điều đó có khả năng. Mặt khác, tại sao bạn muốn làm điều đó? Định nghĩa này bản lề về nó được in và in một chuỗi đảo ngược hiếm khi hữu ích. Là một phần của thuật toán, các yêu cầu của bạn có thể hoàn toàn khác nhau.
Martijn

19
Trong khi điều này làm rất tốt công việc giải thích vấn đề, câu trả lời thực tế là ở một lâu đài khác . Như @ r0estir0bbe đã nói hơn một năm trước, mã liên quan nên có trong câu trả lời, không chỉ liên kết.
TJ Crowder

4
"Hy vọng, điều này giải thích tại sao tất cả các câu trả lời được đăng cho đến nay đều sai" - Khẳng định này là imo quá mạnh mẽ. Nhiều trường hợp sử dụng không yêu cầu hỗ trợ UTF-16 (ví dụ đơn giản; làm việc với các thành phần / tham số URL và URL). Một giải pháp không "sai" đơn giản vì nó không xử lý một kịch bản không bắt buộc. Đáng chú ý, câu trả lời được bình chọn hàng đầu tuyên bố rõ ràng rằng nó chỉ hoạt động với các ký tự ASCII và do đó chắc chắn không có một chút sai.
aroth

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

hoặc là

String.prototype.reverse_string = function() {
    var s = "";
    var i = this.length;
    while (i>0) {
        s += this.substring(i-1,i);
        i--;
    }
    return s;
}

Tôi hoàn toàn đồng ý với nguyên mẫu String.
Jeff Meatball Yang

3
nối chuỗi là đắt tiền. Tốt hơn để xây dựng một mảng và tham gia nó hoặc sử dụng concat ().
Bjorn

2
# 1 là tốt nhất, # 2 có thể chậm kinh khủng
adamJLev

9
Tuy nhiên, không có giải pháp nào hoạt động khi có các ký tự ghép Unicode.
Eric Grange

2
@JuanMendes Tôi đã để lại bình luận đó vào năm 2009, mọi thứ đã thay đổi trong 4 năm qua. : P
Bjorn

62

Phân tích chi tiết và mười cách khác nhau để đảo ngược một chuỗi và chi tiết hiệu suất của chúng.

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

Hiệu quả của những triển khai này:

(Các) triển khai thực hiện tốt nhất trên mỗi trình duyệt

  • Chrome 15 - Ý tưởng 1 và 6
  • Firefox 7 - Thực hiện 6
  • IE 9 - Thực hiện 4
  • Opera 12 - Thực hiện 9

Dưới đây là những triển khai:

Thực hiện 1:

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

Thực hiện 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('');
}

Thực hiện 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('');
}

Thực hiện 4:

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

Thực hiện 5:

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

Thực hiện 6:

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

Thực hiện 7:

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

Thực hiện 8:

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

Thực hiện 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('');
    }

Thực hiện 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));
}

53

Toàn bộ "đảo ngược một chuỗi tại chỗ" là một câu hỏi phỏng vấn cổ của các lập trình viên C, và những người được họ phỏng vấn (để trả thù, có thể?), Sẽ hỏi. Thật không may, đó là phần "Tại chỗ" không còn hoạt động vì các chuỗi trong hầu hết mọi ngôn ngữ được quản lý (JS, C #, v.v.) sử dụng các chuỗi bất biến, do đó đánh bại toàn bộ ý tưởng di chuyển một chuỗi mà không phân bổ bất kỳ bộ nhớ mới nào.

Mặc dù các giải pháp ở trên thực sự đảo ngược một chuỗi, nhưng chúng không làm điều đó mà không phân bổ thêm bộ nhớ và do đó không thỏa mãn các điều kiện. Bạn cần có quyền truy cập trực tiếp vào chuỗi như được phân bổ và có thể thao tác vị trí bộ nhớ ban đầu của nó để có thể đảo ngược nó tại chỗ.

Cá nhân, tôi thực sự ghét những loại câu hỏi phỏng vấn này, nhưng thật đáng buồn, tôi chắc chắn rằng chúng ta sẽ tiếp tục gặp chúng trong nhiều năm tới.


7
Ít nhất tôi có thể nói rằng tôi đã có một người phỏng vấn một lúc trước khá ấn tượng khi anh ấy hỏi tôi làm thế nào để đảo ngược chuỗi "tại chỗ" trong JS và tôi đã giải thích tại sao điều đó là không thể vì các chuỗi trong JS là bất biến. Tôi không biết đó là câu trả lời mà anh ấy mong đợi hay tôi đã giáo dục anh ấy một chút. Dù bằng cách nào nó cũng hoạt động ổn;)
Chev

1
Có lẽ anh ta có nghĩa là "được quản lý" bởi một người thu gom rác, ít nhất đó là những gì thường có nghĩa là "ngôn ngữ được quản lý" hoặc sự hiện diện của Máy ảo / Môi trường thời gian chạy ảo? @torazaburo
AntonB

39

Đầu tiên, sử dụng Array.from()để biến một chuỗi thành một mảng, sau đó Array.prototype.reverse()đảo ngược mảng và sau đó Array.prototype.join()làm cho nó trở lại một chuỗi.

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

Đó là chi phí, nhưng đây là một giải pháp tao nhã! Không có sự viết lại của reverselogic có sẵn .
Gershom

2
@felixfbecker Không, string.split('')không hoạt động. Xem câu trả lời này để giải thích thêm.
Michał Perłakowski

5
Đây phải là câu trả lời được chấp nhận vì nó cũng hoạt động với unicode. Ví dụ: từ ví dụ trên:Array.from('foo 𝌆 bar mañana mañana').reverse().join('') == 'anãnam anañam rab 𝌆 oof'
Julian TF

3
@JulianTF Không chính xác, một dấu ngã vẫn được áp dụng cho 'a' thay vì 'n'.
La Mã Boiko

2
@RomanBoiko Đúng, nhưng bạn có thể bình thường hóa chuỗi đầu tiên. Array.from('foo 𝌆 bar mañana mañana'.normalize('NFC')).reverse().join('')sẽ trở thành"anañam anañam rab 𝌆 oof"
Mr Lister

26

Trong ECMAScript 6, bạn có thể đảo ngược chuỗi nhanh hơn mà không cần sử dụng .split('')phương thức phân tách, với toán tử trải rộng như vậy:

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

1
ES6 cũng cho phép bạn sử dụng hai backticks `` thay vì('')

không có lý do để sử dụng hai backticks trong trường hợp này
Vic

1
Trừ khi bạn đang chơi golf, bạn nên tránh điều này. Viết string.split('')là rõ ràng cho hầu hết mọi người hơn [...string].
AnnanFay

1
@AnnanFay .split('')có vấn đề với các ký tự từ các mặt phẳng bổ sung (các cặp thay thế trong UTF-16), vì nó phân tách theo đơn vị mã UTF-16 thay vì điểm mã . Toán tử lây lan và Array.from()(ưu tiên của tôi) không.
Inkling

@Inkling Tôi không nhận ra đó là một vấn đề. Cảm ơn đã chỉ ra điều đó. Tôi vẫn muốn viết một hàm tiện ích cho rõ ràng.
AnnanFay

19

Có vẻ như tôi trễ 3 năm đến bữa tiệc ...

Thật không may, bạn không thể như đã được chỉ ra. Xem chuỗi JavaScript có bất biến không? Tôi có cần một "trình tạo chuỗi" trong JavaScript không?

Điều tốt nhất tiếp theo bạn có thể làm là tạo một "khung nhìn" hoặc "trình bao bọc", lấy một chuỗi và giới thiệu lại bất kỳ phần nào của API chuỗi bạn đang sử dụng, nhưng giả vờ chuỗi bị đảo ngược. Ví dụ:

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

Bản giới thiệu:

> 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"

Các kicker - sau đây được thực hiện tại chỗ bằng toán học thuần túy, chỉ truy cập mỗi nhân vật một lần và chỉ khi cần thiết:

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

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

Điều này mang lại khoản tiết kiệm đáng kể nếu áp dụng cho một chuỗi rất lớn, nếu bạn chỉ lấy một lát tương đối nhỏ.

Điều này có đáng hay không (đảo ngược như một bản sao như trong hầu hết các ngôn ngữ lập trình) tùy thuộc vào trường hợp sử dụng của bạn và cách bạn thực hiện lại chuỗi API hiệu quả. Ví dụ: nếu tất cả những gì bạn muốn là thực hiện thao tác chỉ mục chuỗi hoặc lấy slices hoặc s nhỏ substr, điều này sẽ giúp bạn tiết kiệm không gian và thời gian. Tuy nhiên, nếu bạn dự định in các lát hoặc lớp nền đảo ngược lớn, thì khoản tiết kiệm có thể thực sự nhỏ, thậm chí còn tệ hơn so với việc thực hiện một bản sao đầy đủ. Chuỗi "đảo ngược" của bạn cũng sẽ không có kiểu string, mặc dù bạn có thể giả mạo chuỗi này bằng nguyên mẫu.

Việc triển khai demo ở trên tạo ra một đối tượng mới có kiểu ReversedString. Nó được tạo nguyên mẫu, và do đó khá hiệu quả, với công việc gần như tối thiểu và không gian tối thiểu (định nghĩa nguyên mẫu được chia sẻ). Đó là một thực hiện lười biếng liên quan đến cắt lát hoãn lại. Bất cứ khi nào bạn thực hiện một chức năng như .slicehoặc .reversed, nó sẽ thực hiện chỉ số toán học. Cuối cùng khi bạn trích xuất dữ liệu (bằng cách gọi ngầm .toString()hoặc.charCodeAt(...) hoặc một cái gì đó), nó sẽ áp dụng những dữ liệu đó theo cách "thông minh", chạm vào ít dữ liệu nhất có thể.

Lưu ý: API chuỗi trên là một ví dụ và có thể không được triển khai hoàn hảo. Bạn cũng có thể sử dụng chỉ 1-2 chức năng mà bạn cần.


13

Có nhiều cách bạn có thể đảo ngược một chuỗi trong JavaScript. Tôi đang ghi lại ba cách tôi thích.

Cách tiếp cận 1: Sử dụng chức năng đảo ngược:

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

Cách tiếp cận 2: Vòng qua các ký tự:

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

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

  return reversed;
}

Cách tiếp cận 3: Sử dụng chức năng giảm:

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

Tôi hi vọng cái này giúp được :)


10

Trong một cuộc phỏng vấn, tôi được yêu cầu đảo ngược một chuỗi mà không sử dụng bất kỳ biến hoặc phương thức riêng nào. Đây là triển khai yêu thích của tôi:

function reverseString(str) {
    return str === '' ? '' : reverseString(str.slice(1)) + str[0];
}

Ngắn, đơn giản, nhưng chậm như địa ngục;)
Tom

13
Phương pháp bản địa bằng không? Thế còn slice? : - /

1
Thú vị sử dụng đệ quy. Trớ trêu rằng đó là trên Stack Overflow. stackoverflow.com/q/2805172/265877
Alex

@Alex, bạn làm cho một điểm tốt. Trong một số trường hợp, người phỏng vấn sẽ yêu cầu bạn không sử dụng Array.prototype.reverse().
Daniel

10

Có nhiều cách để làm điều đó, bạn có thể kiểm tra như sau,

1. Vòng lặp truyền thống (tăng dần):

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

2. Vòng lặp truyền thống (giảm dần):

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. Sử dụng vòng lặp for-of

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

4. Sử dụng phương thức mảng forEach / thứ tự cao:

function reverseString(str){

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

5. Tiêu chuẩn ES6:

function reverseString(str){

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

6. Cách mới nhất:

function reverseString(str){

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

alert(reverseString("Learning JavaScript"));

7. Bạn cũng có thể nhận được kết quả bằng cách sử dụng sau đây,

function reverseString(str){

  return str.split("").reduce((revString, char)=> char + revString, "");
 
}
alert(reverseString("Learning JavaScript"));


7

Trong ES6, bạn có thêm một tùy chọn

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

reverseString('Hello');

6

Đây là cách dễ nhất tôi nghĩ

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
Thật tuyệt khi bạn đã bao gồm một biểu tượng cảm xúc trong ví dụ của mình. Vì vậy, chúng tôi nhanh chóng thấy rằng điều này rõ ràng không hoạt động đối với biểu tượng cảm xúc và rất nhiều ký tự unicode khác.
Íhor Mé

Đức tin, trong khi câu trả lời của bạn là chính xác, tôi không đồng ý rằng đó là cách dễ nhất. Một số câu trả lời đầu tiên sử dụng Array.prototype.reverse()đó sẽ là cách dễ nhất, do đó là câu trả lời phổ biến nhất. Tất nhiên, nó sẽ đòi hỏi kiến ​​thức tốt về JavaScript.
Daniel

6
var str = 'sample string';
[].map.call(str, function(x) {
  return x;
}).reverse().join('');

HOẶC LÀ

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

// Kết quả: 'gnumps elpmas'


Toàn bộ phần 'map` của bạn có thể được viết dưới dạng [...str].

5

Tôi biết rằng đây là một câu hỏi cũ đã được trả lời tốt, nhưng để giải trí cho riêng tôi, tôi đã viết chức năng đảo ngược sau đây và nghĩ rằng tôi sẽ chia sẻ nó trong trường hợp nó hữu ích cho bất kỳ ai khác. Nó xử lý cả cặp thay thế và dấu kết hợp:

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('');
}

Tất cả các đạo cụ cho Mathias, Punycode và nhiều tài liệu tham khảo khác để dạy tôi về sự phức tạp của mã hóa ký tự trong JavaScript.



3

Nếu bạn không muốn sử dụng bất kỳ chức năng tích hợp nào. Thử cái này

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

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

console.log(newstring);

2

Câu trả lời thực sự là: bạn không thể đảo ngược nó tại chỗ, nhưng bạn có thể tạo một chuỗi mới ngược lại.

Cũng giống như một bài tập để chơi với đệ quy: đôi khi khi bạn đi phỏng vấn, người phỏng vấn có thể hỏi bạn cách thực hiện điều này bằng cách sử dụng đệ quy và tôi nghĩ "câu trả lời ưa thích" có thể là "Tôi không muốn làm điều này trong đệ quy có thể dễ dàng gây ra tràn ngăn xếp "(bởi vì nó O(n)đúng hơn O(log n). Nếu có O(log n), khá khó khăn để có được tràn ngăn xếp - 4 tỷ mục có thể được xử lý bởi cấp độ ngăn xếp là 32, vì 2 ** 32 là 4294967296. Nhưng nếu nó làO(n) , nó có thể dễ dàng bị tràn stack.

Đôi khi người phỏng vấn vẫn sẽ hỏi bạn, "giống như một bài tập, tại sao bạn vẫn không viết nó bằng cách sử dụng đệ quy?" Và đây là:

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

chạy thử nghiệm:

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

đầu ra:

999elppa899elppa...2elppa1elppa0elppa

Để thử tràn ngăn xếp, tôi đã đổi 1000thành 10000Google Chrome và báo cáo:

RangeError: Maximum call stack size exceeded

2

Bản thân các chuỗi là bất biến, nhưng bạn có thể dễ dàng tạo một bản sao đảo ngược với mã sau:

function reverseString(str) {

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

  var strReverse = strArray.join("");

  return strReverse;
}

reverseString("hello");

2
//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

1
Điều này có lợi thế là nó xử lý các ký tự mặt phẳng bổ sung một cách chính xác.

2

Một hàm nhỏ xử lý cả kết hợp dấu phụ và ký tự 2 byte:

(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()
  {
    var output = "",
        i      = this.length - 1,
        width;

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

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

      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
].forEach(
  function(str){ console.log( str + " -> " + str.reverse() ); }
);
  


Cập nhật

Một danh sách đầy đủ hơn về kết hợp dấu phụ là:

      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);
      };

Một nỗ lực xứng đáng, nhưng nếu bạn quét tệp UnicodeData.txt, bạn sẽ thấy rằng có 316 phạm vi kết hợp các dấu phụ như vậy, thay vì 5.
Mr Lister

@MrLister Giải pháp sau đó là chỉnh sửa isCombiningDiacriticchức năng để bao gồm tất cả phạm vi 316; vui lòng cung cấp chỉnh sửa đó vì bạn dường như có dữ liệu trong tay.
MT0

1
function reverseString(string) {
    var reversedString = "";
    var stringLength = string.length - 1;
    for (var i = stringLength; i >= 0; i--) {
        reversedString += string[i];
    }
    return reversedString;
}

1

không chuyển đổi chuỗi thành mảng;

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());

sử dụng Array.reverse mà không chuyển đổi ký tự thành điểm mã;

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());

Đối với phiên bản thứ hai: var c = array[i-1]; array[i-1] = array[i]; array[i] = c;không yêu cầu ghép cặp mã. Ngoài ra, vòng lặp for sẽ bắt đầu lúc 1.
MT0

Phiên bản thứ hai không hoạt động với '\ud83c\ud83c\udfa5'.reverse()- nó sẽ xuất ra giống như đầu vào. Thêm vào ++i;trong iftuyên bố nên sửa lỗi này.
MT0

Trên suy nghĩ thứ hai - điều này không xử lý kết hợp dấu phụ: 'a\u0303bc'.reverse() === 'cba\u0303'nên trả về đúng.
MT0

1

Tôi nghĩ String.prototype.reverse là một cách tốt để giải quyết vấn đề này; mã như dưới đây;

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";

1

Sử dụng các hàm Array,

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

1
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);

Làm thế nào là "tại chỗ" ??
Sudhansu Choudhary

1

Nỗ lực ban đầu của riêng tôi ...

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


1

Giữ nó KHÔ và đơn giản ngớ ngẩn !!

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;
}

1

OK, khá đơn giản, bạn có thể tạo một hàm với một vòng lặp đơn giản để thực hiện đảo ngược chuỗi cho bạn mà không cần sử dụng reverse(), charAt()v.v. như thế này:

Ví dụ: bạn có chuỗi này:

var name = "StackOverflow";

Tạo một chức năng như thế này, tôi gọi nó là 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;
}

Và bạn có thể gọi nó như:

reverseString(name);

Và kết quả sẽ là:

"wolfrevOkcatS"

1

Cách tốt nhất để đảo ngược một chuỗi trong JavaScript

1) Array.reverse:

Có lẽ bạn đang suy nghĩ, chờ đã, tôi nghĩ rằng chúng ta đang đảo ngược một chuỗi, tại sao bạn lại sử dụng phương thức Array.reverse. Sử dụng phương thức String.split, chúng tôi đang chuyển đổi chuỗi của mình thành một mảng các ký tự. Sau đó, chúng tôi đang đảo ngược thứ tự của từng giá trị trong mảng và cuối cùng chúng tôi chuyển đổi Mảng trở lại thành Chuỗi bằng phương thức Array.join.

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

2) Giảm vòng lặp while:

Mặc dù khá dài dòng, giải pháp này có ưu điểm so với giải pháp một. Bạn không tạo một mảng và bạn chỉ nối một chuỗi dựa trên các ký tự từ chuỗi nguồn.

Từ góc độ hiệu suất, điều này có thể sẽ mang lại kết quả tốt nhất (mặc dù chưa được kiểm tra). Đối với các chuỗi cực dài, mặc dù hiệu suất có thể giảm ra khỏi cửa sổ.

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

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


    return temp;
}
reverseString('dwayne');

3) Đệ quy

Tôi thích cách đơn giản và rõ ràng giải pháp này là. Bạn có thể thấy rõ rằng các phương thức String.charAt và String.substr đang được sử dụng để truyền qua một giá trị khác nhau bằng cách gọi chính nó mỗi lần cho đến khi chuỗi trống mà ternary sẽ trả về một chuỗi rỗng thay vì sử dụng đệ quy để gọi chính nó . Điều này có thể sẽ mang lại hiệu suất tốt thứ hai sau giải pháp thứ hai.

function reverseString(str) {
    return (str === '') ? '' : reverseString(str.substr(1)) + str.charAt(0);
}
reverseString('dwayne');
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.