引言:一道“简单题”,能让你原地崩溃?
走进腾讯的大楼,坐在面试官面前,面试官看着你,淡淡地抛出第一个考题:
“用 JS 把 'hello' 反向输出成 'olleh'。”
你以为是送分题,结果写着写着就懵了。这题看似简单,其实暗藏玄机,考验的不只是你会不会写代码,而是你对 JavaScript 的理解有多深。
今天我们就来聊聊这个“反转字符串”的骚操作,顺便带你搞懂 JS 中的一些知识点。
一、怎么把 "hello" 变成 "olleh"?
✅ 最常见做法:split + reverse + join,三连出击!
let str = "hello";
let reversed = str.split("").reverse().join("");
console.log(reversed); // 输出 olleh
这是一个层层递进的过程,我们一步步拆解:
-
split(""):把字符串“拆开”,变成一个字母数组。"hello"→['h', 'e', 'l', 'l', 'o']
-
reverse():给这个数组来个翻转,把头变成尾,把尾变成头。['h', 'e', 'l', 'l', 'o']→['o', 'l', 'l', 'e', 'h']
-
join(""):再把这些字母拼回字符串。['o', 'l', 'l', 'e', 'h']→"olleh"
这一套操作下来,一个反向字符串就诞生了。
❗ 为什么不能直接 str.reverse()?
那么问题来了,都能直接翻转,为啥不能直接str.reverse,然后返回它的值呢?这不是减少了工作量吗?
你可能会想:“数组都能 reverse,字符串为啥不行?”
嗯……JS 表示它也很无奈。
因为字符串是“基本类型”,就像数字一样,它们不是对象,也没有自己的方法。你想调用 .reverse()?不好意思,没有这个功能。
但 JS 很贴心地偷偷帮你“包装了一下”,这就是传说中的——
二、包装类:JS 的“临时演员”机制
想象一下,当你写:
"hello".toUpperCase(); // HELLO
你其实是在和一个“假对象”打交道。
JavaScript 背后偷偷干了这些事:
- 创建一个临时的
new String("hello")对象; - 在这个对象上调用
.toUpperCase();( tips:toUpperCase()方法是将字符串对象转化为全大写 ) - 然后立刻把这个对象销毁。
⚠️ 所以,别想着给字符串加属性:
"abc".name = "test";
console.log("abc".name); // undefined —— 对于一个简单数据类型,它接受不了这些属性
三、进阶玩法:判断一个字符串是不是“回文”
什么是回文?就是正着读和倒着读都一样的字符串,比如:
"madam""level""上海自来水来自海上""yzx被女朋友说是M"
听起来很高大上?其实原理很简单,还是那几个老朋友:
function isPalindrome(str) {
const cleaned = str.toLowerCase();
const reversed = cleaned.split("").reverse().join("");
return cleaned === reversed;
}
来测几个例子:
console.log(isPalindrome("madam")); // true
console.log(isPalindrome("hello")); // false
console.log(isPalindrome("Level")); // true(忽略大小写)
console.log(isPalindrome("上海自来水来自海上")); // true(中文也能行)
console.log(isPalindrome("yzx被女朋友说是M")); // false(中英文混合也能行)
是不是有种“原来如此”的感觉?
四、总结:小技巧也能玩出花
| 方法 | 干啥用的 |
|---|---|
split("") | 把字符串拆成一个个字符 |
reverse() | 数组专属技能,反转顺序 |
join("") | 把字符重新拼成字符串 |
| 包装类 | 让字符串假装是个对象 |
别看这些方法简单,它们在js中可是相当重要的。
五、课后挑战:你能更进一步吗?
试试看这些变体题:
-
写一个函数,只保留字母并忽略空格、标点后判断是否是回文。
isPalindrome("A man, a plan, a canal: Panama") // 应该返回 true
- 首先我们要把标点符号去掉;
- 接着把所有字母变成小写或大写
- 最后判断是否回文串
这里就要借用一下replace方法了
replace方法:replace 是 JavaScript 字符串对象的一个方法,用于在字符串中查找匹配的子字符串,并将其替换为指定的新字符串。调用方式为:replace(a,b);其中a为一个字符串或一个表达式,用于指定要查找那=哪些内容,而b是一个字符串或一个函数,用于替换前面a的内容。在 JavaScript 中,正则表达式通常用斜杠 // 包裹。
function isPalindrome(str) {
const cleaned = str.toLowerCase().replace(/[^a-z]/g, '');
// ^ :在方括号 [] 内使用时,它表示取反。也就是说,匹配除了方括号内指定字符之外的所有字符。
// a-z :表示从字母 a 到字母 z 的所有小写字母。
// g :是一个修饰符,代表全局匹配(global)。这意味着正则表达式会在整个字符串中查找所有匹配项,
而不是找到第一个匹配项就停止。
const reversed = cleaned.split('').reverse().join('');
return cleaned === reversed;
}
2. 写一个函数,找出最长回文子串。
使用中心扩展法来查找字符串 s 中的最长回文子串。
变量初始化
let start = 0 , maxLength = 0 ;
- start :用于记录最长回文子串的起始索引,初始值为 0。
- maxLength :用于记录最长回文子串的长度,初始值为 0。
expandAroundCenter 函数
function expandAroundCenter ( left , right ){
while ( left >= 0 && right < s.length && s[left] === s[right]){
left -- ;
right ++ ;
}// 回退一步才是有效的回文范围
const length = right - left - 1 ;
if ( length > maxLength ) {
maxLength = length ;
start = left + 1 ;
}
}
- 功能 :以 left 和 right 为中心向两边扩展,找出以该中心的最长回文子串,并更新 maxLength 和 start 。
- 参数 :
- left :回文中心的左索引。
- right :回文中心的右索引。
- 实现细节 :
- while 循环:只要 left 不越界(大于等于 0)、 right 不越界(小于字符串长度)且左右字符相等,就继续向两边扩展。
- 计算长度:循环结束后,由于最后一次扩展使得 left 和 right 超出了回文范围,所以需要回退一步,即 length = right - left - 1 。
- 更新 maxLength 和 start :如果当前回文子串的长度大于 maxLength ,则更新 maxLength 为当前长度,并将 start 更新为当前回文子串的起始索引 left + 1 。
遍历字符串
for (let i = 0 ; i < s . length;i++ ) {
expandAroundCenter ( i , i ) ; // 奇数长度回文
expandAroundCenter ( i , i + 1 ) ; // 偶数长度回文
}
- 使用 for 循环遍历字符串的每个字符。
- 对于每个字符 i ,分别调用 expandAroundCenter 函数两次:
- expandAroundCenter(i, i) :以单个字符 i 为中心,查找奇数长度的回文子串。
- expandAroundCenter(i, i + 1) :以相邻的两个字符 i 和 i + 1 为中心,查找偶数长度的回文子串。
返回结果
return s . slice ( start , start + maxLength ) ;
- 使用 slice 方法从字符串 s 中提取从 start 开始,长度为 maxLength 的子串,即最长回文子串。
| 题目 | 学到了什么 |
|---|---|
| 忽略标点判断回文 | 正则表达式、字符串清洗、基础逻辑处理 |
| 找最长回文子串 | 算法思维、双指针技巧、字符串操作 |
六、结语:别被“简单题”骗了!
你以为这只是一个小反转字符串的问题?不,这是 JS 基础功的大阅兵!
从字符串的操作到数组的方法,再到 JS 的底层机制——包装类,这一套流程走下来,你就已经从小白升级成了“基础王者”。
所以啊,别小看这些“初级题”,它们才是通往高手之路的关键一步!