楼上说的很清楚了,你的换行符是转义了,所以 eval 出来就相当于两行代码,一行各一个双引号,JS 双引号不能换岗,所以报错。 假如你想要让 eval “看到” "\n",应该不转义换行符,那么就是 \\n一些可能没说清楚的地方: 说字符串 \n 在内存中是数字 10 是正确的,说内存里存了一个换行符也没有问题,这是从不同层面观察字符串。如果更进一步,内存其实也不认识数字 10,只认识二进制数 1010。我之前用 10 来表示换行符主要是帮助区分 JS 代码中的 \n 和实际储存的换行符字符。实际使用时一般不用特别关注编码层面。我觉得你可能不太理解字符串的原理,说不清楚。 请暂时先忘记一切你已经学到的正确或者错误的有关转义的知识。让我们看一下这个字符串(为了方便字符串用高亮表示,并且不再用引号包裹)nnn,里面有 3 个字符。 很容易想到储存的时候分成三个字符:012nnn需要注意的是你的内存并不知道什么是 n,他只认识数字,所以我们把 n 编码成数字,在 ASCII 中也就是 110,那么储存的方式如下(你可以通过 string.charCodeAt(m) 获取字符串第 m 个字符的编码,"n".charCodeAt(0) === 110)总之接下来的表格将不会出现 n 或者别的字符串,只有数字012110110110接下来考虑储存三个换行符。换行也是一个字符,所以在内存中我们也要用一个数字来表示它。由于你现在忘记了什么是转义,不能通过 charCodeAt 获取换行的编码,偷偷告诉你是 10。(回车是 13,不要混淆)012101010那怎么在 JS 中表示三个换行符构成的字符串?人们很快发现在引号之间空两行可以完成这个任务,但立刻又发现这种方法非常易错和不优雅。 所以人们发明了转义,也就是用普通的,人类可读而且比较容易在键盘上摸到的字符【表示】特殊字符。到目前为止似乎都是浅显易懂的内容,也确实是浅显易懂的内容。人们告诉 JS 解析器:当你在俩引号直接读到 一个捺斜杠 \ 接着一个 n 的时候,你既不要把 \ 塞进内存,也不要把 n 塞进内存,而是把一个换行符,也就是整数 10 塞进内存。所以 JS 在解析阶段,就把 \ 和 n 都扔了,只剩下 10。这也就回答了你转义是什么时候发生的,的问题。所以现在可以很开心地使用 console.log("new\nline") 了,可以看到打印了两行,一行是 new,一行是 line,中间是什么呢?是一个换行符。好,目前在你并没有注意到(99%)的情况下已经出现了三种换行符。【解析器认识的东西】一个捺斜杠 \ 接着一个 n【内存认识的东西】整数 10。【你认识的东西】屏幕上空了一行3 放在一边不管,现在我严重怀疑你分不清 1 和 2,所以我把 2 的描述从通常的 一个换行符字符 改成了整数 10。再看 eval,有人会告诉你 eval 能帮你动态执行一些代码。但是 eval 的原理是什么?他一个函数,何德何能执行代码啊?(当然 jsjs 可以做到)他肯定是把活给了解析器啊。观察以下代码:console.log("new\nline") eval('console.log("new\\nline")')我们分析一下代码中的 n 和换行符是如何被处理的(因为我只查了这两个字符的编码值)console.log("new\nline") --^ 普通的 n,是函数名的一部分。不在字符串里,所以没有惨遭变成数字 的命运。 -------------^ 字符串中的 n,被解析器用残忍的手段变成了 110。 -----------------^ 字符串中且在斜杠后面的 n,两个一起变成了 10。 --------------------^ 也很普通。 ------------------------^ 程序中的换行,假如没有它,就得在下一行 eval 前面加个分号。 +^-^+ 所以传给 console.log 的是什么呢? 一列整数:(? 是我没查的编码值) 110 ? ? 10 ? ? 110 ? eval('console.log("new\\nline")') --------^ 在字符串中!110 -------------------^ 在同一个字符串中!110 ------------------------^ 还在那个字符串中,前面有斜杠!但是斜杠自身被另一个斜杠转义了,失去了转义 n 的功能。110 ---------------------------^ 110 +^-^+ 咦?全是 110?我的 10 在哪?(如果你是这么想的,恭喜你已经理解了【字符】的本质:数字而已。 还没有完:eval 会把接收到的字符串传给解析器,第二轮解析开始。 console.log("new\nline") +^-^+ 竟然和第一行一样了! 如果我们没有转义斜杠会发生什么呢?eval 会收到一个引号中间的,致命的 10。也就是在你的字符串中间出现了一个换行,而且字符串不是用反引号 ` 包裹的。 console.log("new line") 这时会发生什么呢? Uncaught SyntaxError: Invalid or unexpected token 跃然屏上。 希望搞懂了,加油(
楼上说的很清楚了,你的换行符是转义了,所以
eval
出来就相当于两行代码,一行各一个双引号,JS 双引号不能换岗,所以报错。假如你想要让
eval
“看到”"\n"
,应该不转义换行符,那么就是\\n
一些可能没说清楚的地方:
说字符串
\n
在内存中是数字 10 是正确的,说内存里存了一个换行符也没有问题,这是从不同层面观察字符串。如果更进一步,内存其实也不认识数字 10,只认识二进制数 1010。我之前用 10 来表示换行符主要是帮助区分 JS 代码中的\n
和实际储存的换行符字符。实际使用时一般不用特别关注编码层面。我觉得你可能不太理解字符串的原理,说不清楚。
请暂时先忘记一切你已经学到的正确或者错误的有关转义的知识。
让我们看一下这个字符串(为了方便字符串用高亮表示,并且不再用引号包裹)
nnn
,里面有 3 个字符。很容易想到储存的时候分成三个字符:
n
n
n
需要注意的是你的内存并不知道什么是
n
,他只认识数字,所以我们把n
编码成数字,在 ASCII 中也就是 110,那么储存的方式如下(你可以通过string.charCodeAt(m)
获取字符串第m
个字符的编码,"n".charCodeAt(0) === 110
)总之接下来的表格将不会出现
n
或者别的字符串,只有数字接下来考虑储存三个换行符。换行也是一个字符,所以在内存中我们也要用一个数字来表示它。由于你现在忘记了什么是转义,不能通过
charCodeAt
获取换行的编码,偷偷告诉你是 10。(回车是 13,不要混淆)那怎么在 JS 中表示三个换行符构成的字符串?人们很快发现在引号之间空两行可以完成这个任务,但立刻又发现这种方法非常易错和不优雅。
所以人们发明了转义,也就是用普通的,人类可读而且比较容易在键盘上摸到的字符【表示】特殊字符。
到目前为止似乎都是浅显易懂的内容,也确实是浅显易懂的内容。
人们告诉 JS 解析器:当你在俩引号直接读到 一个捺斜杠
\
接着一个n
的时候,你既不要把\
塞进内存,也不要把n
塞进内存,而是把一个换行符,也就是整数 10 塞进内存。所以 JS 在解析阶段,就把
\
和n
都扔了,只剩下 10。这也就回答了你转义是什么时候发生的,的问题。所以现在可以很开心地使用
console.log("new\nline")
了,可以看到打印了两行,一行是new
,一行是line
,中间是什么呢?是一个换行符。好,目前在你并没有注意到(99%)的情况下已经出现了三种换行符。
\
接着一个n
3 放在一边不管,现在我严重怀疑你分不清 1 和 2,所以我把 2 的描述从通常的 一个换行符字符 改成了整数 10。
再看
eval
,有人会告诉你eval
能帮你动态执行一些代码。但是eval
的原理是什么?他一个函数,何德何能执行代码啊?(当然 jsjs 可以做到)他肯定是把活给了解析器啊。观察以下代码:
我们分析一下代码中的
n
和换行符是如何被处理的(因为我只查了这两个字符的编码值)