Is there any reason I should use string.charAt(x)
instead of the bracket notation string[x]
?

- 289,723
- 53
- 439
- 496
-
5*Word of caution*: using either syntax for emojis or any other unicode characters past the [Basic Multilingual Plane BPM](https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane) (AKA [the "Astral Plane"](https://www.quora.com/Why-are-unicode-characters-outside-the-BMP-called-astral)) `"".charAt(0)` will return an unusable character – KyleMit Mar 28 '19 at 20:51
-
1@KyleMit `""[0]` also returns an unusable character. – Donald Duck Aug 16 '20 at 13:14
-
6@DonaldDuck - right - hence *using **either** syntax for emojis... will return an unusable character*. – KyleMit Aug 16 '20 at 16:12
-
1@KyleMit (and other readers): That’s why `Array.from("")[0]` or `[...""][0]` should be used in this case. This still won’t work for more complex grapheme clusters, but TC39 proposals exist to simplify this. – Sebastian Simon Sep 25 '21 at 14:22
7 Answers
Bracket notation now works on all major browsers, except for IE7 and below.
// Bracket Notation
"Test String1"[6]
// charAt Implementation
"Test String1".charAt(6)
It used to be a bad idea to use brackets, for these reasons (Source):
This notation does not work in IE7. The first code snippet will return undefined in IE7. If you happen to use the bracket notation for strings all over your code and you want to migrate to
.charAt(pos)
, this is a real pain: Brackets are used all over your code and there's no easy way to detect if that's for a string or an array/object.You can't set the character using this notation. As there is no warning of any kind, this is really confusing and frustrating. If you were using the
.charAt(pos)
function, you would not have been tempted to do it.

- 30,033
- 48
- 152
- 225
-
33True, the notation does not work in IE7, but that's not a huge disadvantage nowadays. Meanwhile, benchmarks I did showed a three time decrease in performance when using charAt vs indexer in Chrome when the string is boxed in an object. I know that's not really relevant, but still worth noting.https://jsfiddle.net/mdasxxd2/ – Siderite Zackwehdex Jul 25 '16 at 10:51
-
7A more accurate test (benchmark.js) https://esbench.com/bench/579609a0db965b9a00965b9e – NoNameProvided Jul 25 '16 at 12:46
-
7Despite being the highest-scored this answer is now (2019) significantly out of date. [The answer below quoting MDN](https://stackoverflow.com/a/5943807/3358139) should be referred to instead. – Scott Martin Feb 14 '19 at 10:57
-
1[No significant performance difference](https://i.stack.imgur.com/nHtX6.png) on Chrome 89 in 2021. – zcoop98 Apr 21 '21 at 21:09
From MDN:
There are two ways to access an individual character in a string. The first is the
charAt
method, part of ECMAScript 3:return 'cat'.charAt(1); // returns "a"
The other way is to treat the string as an array-like object, where each individual characters correspond to a numerical index. This has been supported by most browsers since their first version, except for IE. It was standardised in ECMAScript 5:
return 'cat'[1]; // returns "a"
The second way requires ECMAScript 5 support (and not supported in some older browsers).
In both cases, attempting to change an individual character won't work, as strings are immutable, i.e., their properties are neither neither "writable" nor "configurable".
str.charAt(i)
is better from a compatibility perspective if IE6/IE7 compatibility is required.str[i]
is more modern and works in IE8+ and all other browsers (all Edge/Firefox/Chrome, Safari 2+, all iOS/Android).
-
22True, ECMA 5 is not yet supported on ALL browsers, but it IS supported on MOST browsers: meaning IE9 and above and all Chrome/Firefox versions: http://kangax.github.io/compat-table/es5/#Property_access_on_strings No JS feature will ever be 100% supported, and I feel that avoiding the use of ECMA 5 features will leave us in the past forever... – Danny R Feb 11 '15 at 13:20
They can give different results in edge cases.
'hello'[NaN] // undefined
'hello'.charAt(NaN) // 'h'
'hello'[true] //undefined
'hello'.charAt(true) // 'e'
The charAt function depends on how the index is converted to a Number in the spec.

- 7,670
- 2
- 16
- 11
-
1Also `'hello'[undefined] // undefined` and `'hello'.charAt(undefined) //h` – Ruan Mendes Feb 25 '16 at 20:58
-
4`null` works like `undefined`, but see this: `"hello"["00"] // undefined` but `"hello".charAt("00") // "h"` and `"hello"["0"] // "h"` – panzi Feb 27 '16 at 19:42
-
29
-
2This also means that `.charAt()` performs an extra conversion for its parameter into a `Number`. FYI, there's almost no performance difference nowadays. – Константин Ван Dec 26 '17 at 12:15
-
14This answer should move up, it actually explains that there is a difference between the 2 methods. The other answers talk about compatibility for IE7 (I mean really?) while this answer explains a very real pitfall. – Storm Muller Sep 18 '18 at 19:24
-
2Also `"hello"[313]` is `undefined` and `"hello".charAt(313)` is `""`. – Donald Duck Feb 22 '19 at 12:22
-
1If anyone is wondering why `"hello".charAt(NaN)` is `'h'`, see [here](https://stackoverflow.com/q/9980608/4284627). – Donald Duck Feb 22 '19 at 12:29
There is a difference when you try to access an index which is out of bounds or not an integer.
string[x]
returns the character at the x
th position in string
if x
is an integer between 0 and string.length-1
, and returns undefined
otherwise.
string.charAt(x)
converts x
to an integer using the process explained here (which basically rounds x
down if x
is a non-integer number and returns 0 if parseInt(x)
is NaN
) and then returns the character at the that position if the integer is between 0 and string.length-1
, and returns an empty string otherwise.
Here are some examples:
"Hello"[313] //undefined
"Hello".charAt(313) //"", 313 is out of bounds
"Hello"[3.14] //undefined
"Hello".charAt(3.14) //'l', rounds 3.14 down to 3
"Hello"[true] //undefined
"Hello".charAt(true) //'e', converts true to the integer 1
"Hello"["World"] //undefined
"Hello".charAt("World") //'H', "World" evaluates to NaN, which gets converted to 0
"Hello"[Infinity] //undefined
"Hello".charAt(Infinity) //"", Infinity is out of bounds
Another difference is that assigning to string[x]
does nothing (which can be confusing) and assigning to string.charAt(x)
is an error (as expected):
var str = "Hello";
str[0] = 'Y';
console.log(str); //Still "Hello", the above assignment did nothing
str.charAt(0) = 'Y'; //Error, invalid left-hand side in assignment
The reason why assigning to string[x]
doesn't work is because Javascript strings are immutable.

- 8,409
- 22
- 75
- 99
String.charAt() is the original standard and works in all the browsers. In IE 8+ and other browsers, you may use bracket notation to access characters but IE 7 and below did not support it.
If somebody really wants to use bracket notation in IE 7, it's wise to convert the string to an array using str.split('')
and then use it as an array, compatible with any browser.
var testString = "Hello";
var charArr = testString.split("");
charArr[1]; // "e"

- 10,032
- 6
- 34
- 48

- 46,289
- 20
- 116
- 131
-
5
-
3This method breaks when dealing with Unicode: http://mathiasbynens.be/notes/javascript-unicode – Jeremy J Starcher Apr 07 '14 at 17:41
-
This method would be inefficient when dealing with really large strings because it would duplicate the data in memory (the original string and the array). – Daniel Nov 12 '15 at 04:14
Very interesting outcome when you test the string index accessor vs the charAt()
method. Seems Chrome is the only browser that likes charAt
more.

- 5,136
- 3
- 34
- 36
-
3This is not the case anymore. `index` is wayyy faster in chrome, too. – mako-taco Jul 19 '18 at 17:22
What is the difference between using charAt(index)
and string[index]
to access a character?
# | index value | charAt (return value) | Bracket notation (return value) |
---|---|---|---|
1 | index >= length | '' |
undefined |
2 | index < 0 | '' |
undefined |
3 | index: falsy | character at 0 | undefined |
4 | index = true | character at 1 | undefined |
5 | Number(index: string) === NaN | character at 0 | undefined |
6 | Number(index: string) !== NaN | character at index | character at index |
7 | index: decimal | character at Math.floor(Number(index)) |
undefined |
Notes:
For
charAt()
,index
is first attempted to be type coerced into a number before the index is searched.- Boolean values are type coerced.
Number(true)
evaluates to 1 andNumber(false)
evaluates to 0. - All falsy values return index 0.
- An array containing a single element [1] or ['1'] when coerced, returns the number. Array containing multiple elements returns
NaN
and the treatment happens as per the table above. - If index is a decimal value, as a number, string or array with one element,
Math.floor(Number(index))
is applied.
- Boolean values are type coerced.
For bracket notation, type coercion is attempted when index provided is a string or an array containing one element.
- Boolean values are not type coerced. So
true
doesn't coerce to1
.true
orfalse
both returnundefined
. - All falsy values except 0, return
undefined
. - Decimal values return
undefined
.
- Boolean values are not type coerced. So
type falsy = null | undefined | NaN | ''
falsy
doesn't include 0 here, as 0 is a valid Number index.
let str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
/** index > str.length */
console.log({ charAt: str.charAt(27) }); // returns ''
console.log({ brackets: str[27] }); // returns undefined
/** index < 0 */
console.log({ charAt: str.charAt(-2) }); // returns ''
console.log({ brackets: str[-2] }); // returns undefined
/** Falsy Values */
// All falsy values, return character at index 0
console.log({ charAt: str.charAt(NaN) }); // returns 'A'
console.log({ charAt: str.charAt(false) }); // returns 'A'
console.log({ charAt: str.charAt(undefined) }); // returns 'A'
console.log({ charAt: str.charAt(null) }); // returns 'A'
console.log({ charAt: str.charAt('') }); // returns 'A'
// All falsy values except 0, return undefined
console.log({ brackets: str[NaN] }); // returns undefined
console.log({ brackets: str[false] }); // returns undefined
console.log({ brackets: str[undefined] }); // returns undefined
console.log({ brackets: str[null] }); // returns undefined
console.log({ brackets: str[''] }); // returns undefined
/** index = Boolean(true) */
console.log({ charAt: str.charAt(true) }); // returns 'B', (character at index 1)
console.log({ brackets: str[true] }); // undefined
/** Type coercion: Failure */
console.log({ charAt: str.charAt('A1') }); // returns 'A' (character at index 0)
console.log({ brackets: str['ABC'] }); // returns undefined
/** Type coercion: Success */
console.log({ charAt: str.charAt('1') }); // returns 'B' (attempts to access index after type coercion)
console.log({ brackets: str['1'] }); // returns undefined (attempts to access index after type coercion)
/** Decimal Values */
console.log({ charAt: str.charAt(1.9) }); // returns 'B', applies Math.floor(Number(index))
console.log({ charAt: str.charAt('1.9') }); // returns 'B', applies Math.floor(Number(index))
console.log({ charAt: str.charAt(['1.9']) }); // returns 'B', applies Math.floor(Number(index))
console.log({ brackets: str[1.9] }); // returns undefined

- 101
- 3