How to programmatically tell if two absolutely positioned elements overlap? - javascript

I don't think there's any such method in the DOM API like element.doesOverlap(otherElement), so I think I have to calculate this by hand, right? Not sure if there are any shortcuts.
If not, what is the method for this? It seems like there's so many ways something could overlap....it would be so many conditionals. Is there a concise way of writing this?
In pseudo code, I have this:
if (
((A.top < B.bottom && A.top >= B.top)
|| (A.bottom > B.top && A.bottom <= B.bottom))
&&
((A.left < B.right && A.left >= B.left)
|| (A.right > B.left && A.right <= B.right))) {
// elements A and B do overlap
}
^Is this the simplest way?

This is essentially and x,y comparison problem. You essentially need to compare the two element by there x,y positions at all boundaries ( top, right, bottom and left ) if they overlap anywhere.
A simple method would be, to test that they don't overlap.
Two items could be considered to overlap if none of the following are true:
- box1.right < box2.left // too far left
- box1.left > box2.right // too far right
- box1.bottom < box2.top // too far above
- box1.top > box2.bottom // too far below

Only really a slight change to what you had.
function checkOverlap(elm1, elm2) {
e1 = elm1.getBoundingClientRect();
e2 = elm2.getBoundingClientRect();
return e1.x <= e2.x && e2.x < e1.x + e1.width &&
e1.y <= e2.y && e2.y < e1.y + e1.height;
}
window.onload = function() {
var a = document.getElementById('a');
var b = document.getElementById('b');
var c = document.getElementById('c');
console.log("a & b: "+checkOverlap(a,b));
console.log("a & c: "+checkOverlap(a,c));
console.log("b & c: "+checkOverlap(b,c));
}
<div id="a" style="width:120px;height:120px;background:rgba(12,21,12,0.5)">a</div>
<div id="b" style="position:relative;top:-30px;width:120px;height:120px;background:rgba(121,211,121,0.5)">b</div>
<div id="c" style="position:relative;top:-240px;left:120px;width:120px;height:120px;background:rgba(211,211,121,0.5)">c</div>

There isn't an easier way. The correct code is this, covering all possible ways two elements can overlap:
const doElementsOverlap = (elementA: any, elementB: any) => {
const A = elementA.getBoundingClientRect();
const B = elementB.getBoundingClientRect();
return (
((A.top < B.bottom && A.top >= B.top)
|| (A.bottom > B.top && A.bottom <= B.bottom)
|| (A.bottom >= B.bottom && A.top <= B.top))
&&
((A.left < B.right && A.left >= B.left)
|| (A.right > B.left && A.right <= B.right)
|| (A.left < B.left && A.right > B.right))
);
};

Related

My Javascript if statements using time variables to display different message at set time periods execute a code block when it shouldn't

I am making an if statement that executes using variables based on the Date() function, but the if statement doesn't appear to prevent execution when it should. The code block is intended to reveal one among a set of possible paragraphs when the time is right. Here is my script
<script>
const D = new Date();
var m = D.getMinutes();
var h = D.getHours();
function showMessage() {
if ((0 < h <= 5) || ((h == 6) && (m == 0))) {
document.getElementById("m1").classList.remove("message");
} else if (((6 == h) && (m != 0)) || (6 < h < 12) || ((h == 12) && (m == 0))) {
document.getElementById("m2").classList.remove("message");
} else if (((12 == h) && (m != 0)) || (12 < h < 18) || ((h == 18) && (m == 0))) {
document.getElementById("m3").classList.remove("message");
} else {
document.getElementById("m4").classList.remove("message");
}
}
showMessage();
</script>
Here is the relevant HTML block:
<div id="messagecontainer">
<p class="message" id="m1">Good morning, you must be an early bird!</p>
<p class="message" id="m2">Good morning</p>
<p class="message" id="m3">Good afternoon</p>
<p class="message" id="m4">Good evening</p>
</div>
And here is the CSS that makes it work:
.message {
display: none;
}
As you can see, when the "message" class is removed from any paragraph, the paragraph should be revealed. I know this part works but the problem is that, it's always revealing the id="m1" paragraph when it shouldn't be. It should only be excuting from 1am (this is a mistake I just noticed and will fix) to 6pm. Otherwise it should go to as many else if statements as necessary until the time is right and the correct text block executes. For example, it is 3:30pm (15h30m) now and therefore the third block with the "m3" paragraph should be showing. But it's still the "m1".
The only things I can think of are that I somehow botched the syntax on the if statements or otherwise the variable scope isn't allowing me access to the variables within the if statements (I believe they should be global but I could be wrong). Can anyone see the problem?
This doesn't do what you think it does:
(0 < h <= 5)
This will evaluate one of the conditions first, then use the result of that condition to evaluate the second one. So you're essentially doing this:
(false <= 5)
Which would be true.
Separate the logical conditions explicitly:
((0 < h) && (h <= 5))
You are writing some conditions that don't work as expected (they work in mathematical notation, but not when writing code).
Take this for example 0 < h <= 5. It will get executed in steps
0 < 5. This can either be true or false
true < 5 or false < 5, both of which will end up being evaluated to true. This is because of how JS converts some values when doing boolean or math operations
You need to split all of this in something like this 0 < h && h <= 5
The first if statement will always result to true
(0 < h <= 5) is equal to ((0 < h) <= 5) and you can check that it will be always true
In JavaScript, to check if a number is between two numbers (what in regular math would be n1 < x < n2), you have to use the && operator
(0 < h) && (h <= 5)
so:
(0 < h <= 5) || ((h == 6) && (m == 0)) is equal to
((0 < h) <= 5) || ((h == 6) && (m == 0))
which is not what you intended because the first two parenthesis will always result in a true value.
What you want is that:
((0 < h) && (h <= 5)) || ((h == 6) && (m == 0))
I would suggest a simplification of the conditional using a ternary and the use the "value" defined as a class and just do it there.
Alternative: toggle with a data attribute (second example)
function showMessage() {
const now = new Date();
const m = now.getMinutes();
const h = now.getHours();
let test = (h <= 5 || (h == 6 && m == 0)) ? "am" :
((h >= 6 && h < 12) || (h == 12 && m == 0)) ? "morning" :
((h >= 12 && m > 0) || (h > 12 && h < 18) || (h == 18 && m == 0)) ? "afternoon" :
"evening";
document.querySelector('.' + test)
.classList.remove("message");
}
showMessage();
.message {
display: none;
}
<div id="messagecontainer">
<p class="message am" id="m1">Good morning, you must be an early bird!</p>
<p class="message morning" id="m2">Good morning</p>
<p class="message afternoon" id="m3">Good afternoon</p>
<p class="message evening" id="m4">Good evening</p>
</div>
Alternate:
function showMessage() {
const now = new Date();
const m = now.getMinutes();
const h = now.getHours();
let test = (h <= 5 || (h == 6 && m == 0)) ? "am" :
((h >= 6 && h < 12) || (h == 12 && m == 0)) ? "morning" :
((h >= 12 && m > 0) || (h > 12 && h < 18) || (h == 18 && m == 0)) ? "afternoon" :
"evening";
document.querySelector('.' + test)
.dataset.toggle = "show";
}
showMessage();
.message {
display: none;
}
.message[data-toggle="show"] {
display: block;
}
<div id="messagecontainer">
<p class="message am">Good morning, you must be an early bird!</p>
<p class="message morning">Good morning</p>
<p class="message afternoon">Good afternoon</p>
<p class="message evening">Good evening</p>
</div>

Dry-er Way of Writing a Bunch of If Else Statements

I have a variable placement that can be set to the following values: top, top-left, top-right, bottom, bottom-left, bottom-right, right, right-top, right-bottom, left, left-top, left-bottom.
I have another variable const trigger = triggerRef.current.getBoundingClientRect(); so I can determine where the trigger element is, and based on that, set the placement variable accordingly.
I am currently using a lot of if else statements. For instance:
if (placement === "top" && trigger.top < 75 && windowWidth - trigger.right > 75 && trigger.left > 175)
{ placement = "bottom";
} else if ( placement === "top" && windowWidth - trigger.right < 75 && windowHeight - trigger.bottom > 75 && trigger.top < 75)
{ placement = "left-top"; }
...and the code goes on and on
What's a "DRY-er" way of doing this?
Consolidate the logic in these tests and only check once. Assign a variable if instead of repeating the same calculations:
if (placement === "top" && trigger.top < 75 ) {
const triggerFromWidth = windowWidth - trigger.right;
if (triggerFromWidth > 75 && trigger.left > 175) {
placement = "bottom";
} else if (triggerFromWidth < 75 && windowHeight - trigger.bottom > 75) {
placement = "left-top";
}
}

Slide Feature: setProperty not working in IE

I'm working on a slide feature and it works great on all browsers except IE of course.
I firstly thought it's because of Math.sign but I've added a polyfill for it and it solve the error, but the slider still didn't work. Then I investigated a bit more and I think it's because of this syntax
_C.style.setProperty('--i', num);
which is used to set a value and use it in CSS like this:
transform: translate(calc(var(--i, 0)/var(--n)*var(--n)*-100%));
function move(e) {
document.getElementsByClassName('checked')[0].classList.remove('checked')
if(x0 || x0 === 0) {
if (!Math.sign) {
Math.sign = function(x) {
return ((x > 0) - (x < 0)) || +x;
}
}
let dx = unify(e).clientX - x0, s = Math.sign(dx);
if((i > 0 || s < 0) && (i < N - 1 || s > 0))
_C.style.setProperty('--i', i -= s);
let circles = document.getElementsByClassName('testimonial-circle')
let circle = circles[i]
circle.classList.add('checked')
x0 = null
}
};
The idea is to click on a bubble and slide to the specific "testimonial"

Check if element is in viewport doesn't work properly

I've got three elements - every element is hidden from the start. If user scrolls onto them, they show up. I wrote a function that checks if element named bubbles is inside viewport. If it is, then function should show the rest of the elements.
But it doesn't. Element boxes is higher than element bubbles, and it also fires a function. But it shouldn't. I have no idea where the problem is.
document.addEventListener("scroll", checkViewport);
function checkViewport() {
var bubbles = document.getElementsByClassName("bubble-chat");
var boxes = document.getElementsByClassName("boxes");
var avatar = document.getElementsByClassName("msg-avatar");
for (let i = 0; i < avatar.length; i++) {
var bounding = bubbles[i].getBoundingClientRect();
if (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.right <= (window.innerWidth || document.documentElement.clientWidth) &&
bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight)
) {
avatar[i].style.opacity = "1";
bubbles[i].style.opacity = "1";
(function(i) {
setTimeout(function() {
bubbles[i].style.display = "none";
boxes[i].style.opacity = "1";
}, 3000);
})(i);
}
}
}
you should also consider the scrolling positioning as the bounding box is relative to that.
Fixed code:
bounding.top >= document.documentElement.scrollTop &&
bounding.left >= 0 &&
bounding.right <= (window.innerWidth || document.documentElement.clientWidth) &&
bounding.bottom <= document.documentElement.scrollTop + (window.innerHeight || document.documentElement.clientHeight)
Well, I feel stupid. The code was okay all the time. I just commented one of the msg-text divs, and turns out, that it was the reason for the code to break.

How do you reverse a string in-place in JavaScript?

How do you reverse a string in-place in JavaScript when it is passed to a function with a return statement, without using built-in functions (.reverse(), .charAt() etc.)?
As long as you're dealing with simple ASCII characters, and you're happy to use built-in functions, this will work:
function reverse(s){
return s.split("").reverse().join("");
}
If you need a solution that supports UTF-16 or other multi-byte characters, be aware that this function will give invalid unicode strings, or valid strings that look funny. You might want to consider this answer instead.
[...s] is Unicode aware, a small edit gives:-
function reverse(s){
return [...s].reverse().join("");
}
The following technique (or similar) is commonly used to reverse a string in JavaScript:
// Don’t use this!
var naiveReverse = function(string) {
return string.split('').reverse().join('');
}
In fact, all the answers posted so far are a variation of this pattern. However, there are some problems with this solution. For example:
naiveReverse('foo 𝌆 bar');
// → 'rab �� oof'
// Where did the `𝌆` symbol go? Whoops!
If you’re wondering why this happens, read up on JavaScript’s internal character encoding. (TL;DR: 𝌆 is an astral symbol, and JavaScript exposes it as two separate code units.)
But there’s more:
// 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.
A good string to test string reverse implementations is the following:
'foo 𝌆 bar mañana mañana'
Why? Because it contains an astral symbol (𝌆) (which are represented by surrogate pairs in JavaScript) and a combining mark (the ñ in the last mañana actually consists of two symbols: U+006E LATIN SMALL LETTER N and U+0303 COMBINING TILDE).
The order in which surrogate pairs appear cannot be reversed, else the astral symbol won’t show up anymore in the ‘reversed’ string. That’s why you saw those �� marks in the output for the previous example.
Combining marks always get applied to the previous symbol, so you have to treat both the main symbol (U+006E LATIN SMALL LETTER N) as the combining mark (U+0303 COMBINING TILDE) as a whole. Reversing their order will cause the combining mark to be paired with another symbol in the string. That’s why the example output had ã instead of ñ.
Hopefully, this explains why all the answers posted so far are wrong.
To answer your initial question — how to [properly] reverse a string in JavaScript —, I’ve written a small JavaScript library that is capable of Unicode-aware string reversal. It doesn’t have any of the issues I just mentioned. The library is called Esrever; its code is on GitHub, and it works in pretty much any JavaScript environment. It comes with a shell utility/binary, so you can easily reverse strings from your terminal if you want.
var input = 'foo 𝌆 bar mañana mañana';
esrever.reverse(input);
// → 'anañam anañam rab 𝌆 oof'
As for the “in-place” part, see the other answers.
String.prototype.reverse_string=function() {return this.split("").reverse().join("");}
or
String.prototype.reverse_string = function() {
var s = "";
var i = this.length;
while (i>0) {
s += this.substring(i-1,i);
i--;
}
return s;
}
Detailed analysis and ten different ways to reverse a string and their performance details.
http://eddmann.com/posts/ten-ways-to-reverse-a-string-in-javascript/
Perfomance of these implementations:
Best performing implementation(s) per browser
Chrome 15 - Implemations 1 and 6
Firefox 7 - Implementation 6
IE 9 - Implementation 4
Opera 12 - Implementation 9
Here are those implementations:
Implementation 1:
function reverse(s) {
var o = '';
for (var i = s.length - 1; i >= 0; i--)
o += s[i];
return o;
}
Implementation 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('');
}
Implementation 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('');
}
Implementation 4:
function reverse(s) {
return s.split('').reverse().join('');
}
Implementation 5:
function reverse(s) {
var i = s.length,
o = '';
while (i > 0) {
o += s.substring(i - 1, i);
i--;
}
return o;
}
Implementation 6:
function reverse(s) {
for (var i = s.length - 1, o = ''; i >= 0; o += s[i--]) { }
return o;
}
Implementation 7:
function reverse(s) {
return (s === '') ? '' : reverse(s.substr(1)) + s.charAt(0);
}
Implementation 8:
function reverse(s) {
function rev(s, len, o) {
return (len === 0) ? o : rev(s, --len, (o += s[len]));
};
return rev(s, s.length, '');
}
Implementation 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('');
}
Implementation 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));
}
Implementation 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')
The whole "reverse a string in place" is an antiquated interview question C programmers, and people who were interviewed by them (for revenge, maybe?), will ask. Unfortunately, it's the "In Place" part that no longer works because strings in pretty much any managed language (JS, C#, etc) uses immutable strings, thus defeating the whole idea of moving a string without allocating any new memory.
While the solutions above do indeed reverse a string, they do not do it without allocating more memory, and thus do not satisfy the conditions. You need to have direct access to the string as allocated, and be able to manipulate its original memory location to be able to reverse it in place.
Personally, i really hate these kinds of interview questions, but sadly, i'm sure we'll keep seeing them for years to come.
First, use Array.from() to turn a string into an array, then Array.prototype.reverse() to reverse the array, and then Array.prototype.join() to make it back a string.
const reverse = str => Array.from(str).reverse().join('');
In ECMAScript 6, you can reverse a string even faster without using .split('') split method, with the spread operator like so:
var str = [...'racecar'].reverse().join('');
Seems like I'm 3 years late to the party...
Unfortunately you can't as has been pointed out. See Are JavaScript strings immutable? Do I need a "string builder" in JavaScript?
The next best thing you can do is to create a "view" or "wrapper", which takes a string and reimplements whatever parts of the string API you are using, but pretending the string is reversed. For example:
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
Demo:
> 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"
The kicker -- the following is done in-place by pure math, visiting each character only once, and only if necessary:
> 'demo: ' + S('0123456789abcdef').slice(3).reversed().slice(1,-1).toUpperCase()
"demo: EDCBA987654"
> S('0123456789ABCDEF').slice(3).reversed().slice(1,-1).toLowerCase().charAt(3)
"b"
This yields significant savings if applied to a very large string, if you are only taking a relatively small slice thereof.
Whether this is worth it (over reversing-as-a-copy like in most programming languages) highly depends on your use case and how efficiently you reimplement the string API. For example if all you want is to do string index manipulation, or take small slices or substrs, this will save you space and time. If you're planning on printing large reversed slices or substrings however, the savings may be small indeed, even worse than having done a full copy. Your "reversed" string will also not have the type string, though you might be able to fake this with prototyping.
The above demo implementation creates a new object of type ReversedString. It is prototyped, and therefore fairly efficient, with almost minimal work and minimal space overhead (prototype definitions are shared). It is a lazy implementation involving deferred slicing. Whenever you perform a function like .slice or .reversed, it will perform index mathematics. Finally when you extract data (by implicitly calling .toString() or .charCodeAt(...) or something), it will apply those in a "smart" manner, touching the least data possible.
Note: the above string API is an example, and may not be implemented perfectly. You also can use just 1-2 functions which you need.
Legible way using spread syntax:
const reverseString = str => [...str].reverse().join('');
console.log(reverseString('ABC'));
There are many ways you can reverse a string in JavaScript. I'm jotting down three ways I prefer.
Approach 1: Using reverse function:
function reverse(str) {
return str.split('').reverse().join('');
}
Approach 2: Looping through characters:
function reverse(str) {
let reversed = '';
for (let character of str) {
reversed = character + reversed;
}
return reversed;
}
Approach 3: Using reduce function:
function reverse(str) {
return str.split('').reduce((rev, char) => char + rev, '');
}
I hope this helps :)
There are Multiple ways of doing it, you may check the following,
1. Traditional for loop(incrementing):
function reverseString(str){
let stringRev ="";
for(let i= 0; i<str.length; i++){
stringRev = str[i]+stringRev;
}
return stringRev;
}
alert(reverseString("Hello World!"));
2. Traditional for loop(decrementing):
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. Using for-of loop
function reverseString(str){
let strn ="";
for(let char of str){
strn = char + strn;
}
return strn;
}
alert(reverseString("Get well soon"));
4. Using the forEach/ high order array method:
function reverseString(str){
let revSrring = "";
str.split("").forEach(function(char){
revSrring = char + revSrring;
});
return revSrring;
}
alert(reverseString("Learning JavaScript"));
5. ES6 standard:
function reverseString(str){
let revSrring = "";
str.split("").forEach(char => revSrring = char + revSrring);
return revSrring;
}
alert(reverseString("Learning JavaScript"));
6. The latest way:
function reverseString(str){
return str.split("").reduce(function(revString, char){
return char + revString;
}, "");
}
alert(reverseString("Learning JavaScript"));
7. You may also get the result using the following,
function reverseString(str){
return str.split("").reduce((revString, char)=> char + revString, "");
}
alert(reverseString("Learning JavaScript"));
During an interview, I was asked to reverse a string without using any variables or native methods. This is my favorite implementation:
function reverseString(str) {
return str === '' ? '' : reverseString(str.slice(1)) + str[0];
}
In ES6, you have one more option
function reverseString (str) {
return [...str].reverse().join('')
}
reverseString('Hello');
This is the easiest way I think
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 🍺'));
var str = 'sample string';
[].map.call(str, function(x) {
return x;
}).reverse().join('');
OR
var str = 'sample string';
console.log(str.split('').reverse().join(''));
// Output: 'gnirts elpmas'
If you don't want to use any built in function. Try this
var string = 'abcdefg';
var newstring = '';
for(let i = 0; i < string.length; i++){
newstring = string[i] += newstring;
}
console.log(newstring);
I know that this is an old question that has been well answered, but for my own amusement I wrote the following reverse function and thought I would share it in case it was useful for anyone else. It handles both surrogate pairs and combining marks:
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('');
}
All props to Mathias, Punycode, and various other references for schooling me on the complexities of character encoding in JavaScript.
You can't because JS strings are immutable. Short non-in-place solution
[...str].reverse().join``
let str = "Hello World!";
let r = [...str].reverse().join``;
console.log(r);
You can't reverse a string in place but you can use this:
String.prototype.reverse = function() {
return this.split("").reverse().join("");
}
var s = "ABCD";
s = s.reverse();
console.log(s);
One new option is to use Intl.Segmenter which allows you to split on the visual graphemes (ie: user-perceived character units such as emojis, characters, etc.). Intl.Segmenter is currently a stage 4 proposal and there is a polyfill available for it if you wish to use it. It currently has limited browser support which you can find more information about here.
Here is how the reverse() method may look if you use Intl.Segmenter:
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
The above creates a segmenter to segment/split strings by their visual graphemes. Calling .segment() on the segmenter with the string input then returns an iterator, which produces objects of the form {segment, index, input, isWordLike}. The segment key from this object contains the string segment (ie: the individual grapheme). To convert the iterator to an array, we use Array.from() on the iterator and extract the segmented graphemes, which can be reversed with .reverse(). Lastly, we join the array back into a string using .join()
There is also another option which you can try that has better browser support than Intl.Segmenter, however isn't as bullet-proof:
const reverse = str => Array.from(str.normalize('NFC')).reverse().join('');
this helps deal with characters consisting of multiple code points and code units. As pointed out in other answers, there are issues with maintaining composite and surrogate pair ordering in strings such as 'foo 𝌆 bar mañana mañana'. Here 𝌆 is a surrogate pair consisting of two code units, and the last ñ is a composite pair consisting of two Unicode characters to make up one grapheme (n+̃ = ñ).
In order to reverse each character, you can use the .reverse() method which is part of the Array prototype. As .reverse() is used on an array, the first thing to do is to turn the string into an array of characters. Typically, .split('') is used for this task, however, this splits up surrogate pairs which are made from up of multiple code units (as already shown in previous answers):
>> '𝌆'.split('')
>> `["�", "�"]`
Instead, if you invoke the String.prototype's Symbol.iterator method then you'll be able to retain your surrogate pairs within your array, as this iterates over the code points rather than the code units of your string:
>> [...'𝌆']
>> ["𝌆"]
The next thing to handle is any composite characters within the string. Characters that consist of two or more code points will still be split when iterated on:
>> [...'ö']
>> ["o", "̈"]
The above separates the base character (o) from the diaresis, which is not desired behavior. This is because ö is a decomposed version of the character, consisting of multiple code points. To deal with this, you can use a string method introduced in ES6 known as String.prototype.normalize(). This method can compose multiple code points into its composed canonical form by using "NFC" as an argument. This allows us to convert the decomposed character ö (o + combining diaeresis) into its precomposed form ö (latin small letter o with diaeresis) which consists of only one code point. Calling .normalize() with "NFC" thus tries to replace multiple code points with single code points where possible. This allows graphemes consisting of two code points to be represented with one code point.
>> [...'ö'.normalize('NFC')]
>> ["ö"]
As normalize('NFC') produces one character, it can then be reversed safely when amongst others. Putting both the spread syntax and normalization together, you can successfully reverse strings of characters such as:
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'));
There are a few cases where the above normalization+iteration will fail. For instance, the character ❤️ (heavy black heart ❤️) consists of two code points. The first being the heart and the latter being the variation selector-16 (U+FE0F) which is used to define a glyph variant for the preceding character. Other characters can also produce similar issues like this.
Another thing to look out for is ZWJ (Zero-width joiner) characters, which you can find in some scripts, including emoji. For example the emoji 👨‍👩‍👦 comprises of the Man, Woman and Boy emoji, each separated by a ZWJ. The above normalization + iteration method will not account for this either.
As a result, using Intl.Segmenter is the better choice over these two approaches. Currently, Chrome also has its own specific segmentation API known as Intl.v8BreakIterator. This segmentation API is nonstandard and something that Chrome simply just implements. So, it is subject to change and doesn't work on most browsers, so it's not recommended to use. However, if you're curious, this is how it could be done:
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
UTF-8 strings can have:
Combining diacritics such as b̃ which composed of the b character and a following ~ diacritic generated by the unicode escape sequnce \u0303;
Multi-byte characters such as 🎥; which is generated by the multi-byte unicode escape sequence \uD83C\uDFA5; and
Multiple characters may be combined together with a zero-width joiner character (given by the unicode escape sequence \u200D). For example, the character 👨‍👩‍👦 can be composed using the individual (multi-byte) emojis 👨 then a zero-width joiner then 👩 then another zero-width joiner then 👦 such that the entire 3-person character is 8-bytes (\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC66).
This will handle reversing all 3 cases and keeping the bytes in the correct order such that the characters are reversed (rather than naively reversing the bytes of the string):
(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() ); }
);
Update
The above code identifies some of the more commonly used combining diacritics. A more complete list of combining diacritics (that could be swapped into the above code) is:
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);
};
function reverseString(string) {
var reversedString = "";
var stringLength = string.length - 1;
for (var i = stringLength; i >= 0; i--) {
reversedString += string[i];
}
return reversedString;
}
I think String.prototype.reverse is a good way to solve this problem;
the code as below;
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";
The real answer is: you can't reverse it in place, but you can create a new string that is the reverse.
Just as an exercise to play with recursion: sometimes when you go to an interview, the interviewer may ask you how to do this using recursion, and I think the "preferred answer" might be "I would rather not do this in recursion as it can easily cause a stack overflow" (because it is O(n) rather than O(log n). If it is O(log n), it is quite difficult to get a stack overflow -- 4 billion items could be handled by a stack level of 32, as 2 ** 32 is 4294967296. But if it is O(n), then it can easily get a stack overflow.
Sometimes the interviewer will still ask you, "just as an exercise, why don't you still write it using recursion?" And here it is:
String.prototype.reverse = function() {
if (this.length <= 1) return this;
else return this.slice(1).reverse() + this.slice(0,1);
}
test run:
var s = "";
for(var i = 0; i < 1000; i++) {
s += ("apple" + i);
}
console.log(s.reverse());
output:
999elppa899elppa...2elppa1elppa0elppa
To try getting a stack overflow, I changed 1000 to 10000 in Google Chrome, and it reported:
RangeError: Maximum call stack size exceeded
Strings themselves are immutable, but you can easily create a reversed copy with the following code:
function reverseString(str) {
var strArray = str.split("");
strArray.reverse();
var strReverse = strArray.join("");
return strReverse;
}
reverseString("hello");
//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
Reverse a String using built-in functions
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'));
Reverse a String without the helpers
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'));
Using Array functions,
String.prototype.reverse = function(){
return [].reduceRight.call(this, function(last, secLast){return last + secLast});
}
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);
My own original attempt...
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

Categories