📖前言
Hello,大家好呀,这里是大厂面试系列,本文通过一道简单题带你深度剖析js中的一些大厂必问的知识点!话不多说,让我们直接开始吧!
✨请听题
题目很简单:
将字符串hello 反向输出 olleh。
看到这里有的大佬会说:这种题不是侮辱我智商吗?这也太简单了, 靠这种题还能去大厂?开玩笑吧!
我要告诉你的是:题目确实很简单,但是大厂面试中是会有一道这种很简单的基础的,但是面试官不仅仅需要你回答出题目的解法,还需要你阐述明白这个题目涉及到的js的知识点,这也是大厂面试官注重的底层能力,所以下文不仅会给出解法,还会详细地介绍其中的js知识点!
🔍一般解法
这个题目确实有很多种解法,我们给出最常见的两种
💡解法一
我们把字符串hello通过split变成数组,然后通过一个指针反向遍历hello的数组,添加每次遍历中指针指向的字符到咱们的结果ans数组中,最后再输出将ans数组通过join转化为咱们的最终答案即可!
const input = "hello";
const arr = input.split('');
const ans = [];
for (let i = arr.length - 1; i >= 0; i--) {
ans.push(arr[i]);
}
console.log(ans.join('')); //olleh
💡解法二
解法一的思路没有问题,但是太麻烦了,实际上js的有一个reverse()的方法可以直接将数组的内容倒置。
const input = "hello";
const ans = input.split('').reverse().join('');
console.log(ans); //olleh
显而易见,解法二的效率更高,那么,通过这道题,我们可以学到什么呢?接下来我就为你详细地介绍JS的奇妙设计!
🤔为什么可以用对象的方法?
🔢简单数据类型与对象
在JS中,数据类型分为两种,分别是
- 简单数据类型(primitive):String、Number、Boolean、Null、undefiend、Symbol
- 对象(Object):除了简单数据类型之外的都是对象
我们可以用typeof的方法查看这个变量或者值到底是简单数据类型的哪一种还是属于复杂数据类型
let i = 30;
console.log(typeof i); //30
console.log(typeof 'I love you'); //string
const cat = {name: 'Tom',age: 2,color: 'brown'};
console.log(typeof cat) //object
❓问题来了
我们现在已知input('hello')是一个简单数据类型string,而不是对象,那为什么input.split('').reverse().join('');其中的input能够在.后面接那么多方法呢?
🎉答案揭晓:自动装箱
不卖关子,直接给出答案,因为自动装箱。
📦啥是自动装箱?
在Java中,自动装箱会为 原始类型(简单类型)临时创建对应的包装对象,以便它们能够调用方法或访问属性。
input是简单数据类型string没错,用.调用方法的只能是对象也没错。实际上,JS引擎在看到input在进行.操作调用方法时,会悄悄地将string这个简单数据类型自动转换成String这个对象,所以实际上是转换后的String在调用方法.split()...。
📋包装对象列表
下面给出JavaScript 中原始类型及其对应的包装对象:
| 原始类型(Primitive) | 对应的包装对象(Wrapper Object) | 示例(自动装箱触发时) |
|---|---|---|
string | String | "hello".toUpperCase() |
number | Number | (42).toFixed(2) |
boolean | Boolean | true.toString() |
symbol | Symbol | Symbol("desc").description |
bigint | BigInt | (10n).toString() |
注意:null 和 undefined 没有对应的包装对象,尝试对它们调用方法会抛出错误(如 null.toString() → TypeError)。
⏳自动装箱的临时性
自动装箱是临时的,调用结束后包装对象会被销毁,结果仍是原始类型。
const str = "hello"; // 原始类型(string)
// 调用 .toUpperCase() 方法时,引擎自动装箱:
const upperStr = str.toUpperCase();
console.log(upperStr); // "HELLO"
console.log(typeof str); // "string"(未被永久转为对象)
下面再给上段代码模拟自动装箱的伪代码,助你更好地理解自动装箱。
const str = "hello";
const upperStr = str.toUpperCase(); // 自动装箱:str → new String(str)
// 引擎内部行为(伪代码):
const tempStrObj = new String(str); // 临时包装对象
const result = tempStrObj.toUpperCase(); // 调用方法
tempStrObj = null; // 销毁临时对象
console.log(result); // "HELLO"(仍是 string 原始类型)
📜JavaScript 的设计哲学
好了,现在我们了解了自动装箱后,也就能理解上文的代码中"string"为什么能够调用方法了?这些其实是JS的设计之一,接下来我们来详谈JS的一些设计吧!
🚫函数式写法的缺失
在大多数编程语言中,我们通常可以使用函数式写法来操作数据,比如用len("hello")获取字符串长度。然而在JavaScript中,这种直接的函数式调用并不存在,我们必须使用"hello".length这样的属性访问方式。这种设计选择反映了JavaScript独特的语言特性。
这种差异源于JavaScript的核心设计理念:它更倾向于使用基于原型的面向对象模式,而非纯粹的函数式编程范式。虽然JavaScript确实包含一些函数式特性(如高阶函数),但在基本操作的设计上,它选择了更贴近面向对象的方式。
🔄自动装箱与设计一致性
有人可能会疑惑:为什么JavaScript既不支持直接的函数式写法,而且还要引入自动装箱机制?这些设计其实时时都体现了JavaScript追求面向对象写法统一性的理念。
JavaScript通过自动装箱机制,让原始类型也能像对象一样使用方法,从而保持了语言使用方式的一致性。这种设计带来了几个重要优势:
- 统一了原始类型和对象的操作方式
- 减少了开发者需要记忆的特殊情况
- 保持了语言的简洁性,同时不牺牲功能
🎭统一的面向对象范式
JavaScript的设计者Brendan Eich在创造这门语言时,选择了以原型为基础的面向对象系统作为核心范式。这种选择决定了JavaScript的许多特性:
- 所有值都可以被视为对象(通过自动装箱)
- 方法调用采用统一的点表示法
- 通过原型链实现继承
这种统一性使得开发者可以用相似的方式处理不同类型的数据,虽然这种设计有时会导致一些看似矛盾的现象(如原始类型调用方法),但从整体语言架构来看,它确实提供了一种高度一致的编程体验。
正因为有了这样的设计,所以咱们的JS是一门学习成本很低的语言。
🎯总结
通过这道简单的字符串反转题目,我们深入剖析了 JavaScript 的核心机制——自动装箱。原始类型(如 string)通过临时包装成对应的 String 对象,实现了方法调用的能力(如 split()、toUpperCase()),而这一过程对开发者完全透明,体现了 JavaScript 统一面向对象 的设计哲学。
这种设计既保持了原始类型的轻量高效,又换来了极高的灵活性和低学习门槛。我相信,理解这些底层逻辑,不仅能应对大厂面试的深度追问,更能真正掌握 JavaScript 的设计精髓。
🌇结尾
感谢你看到最后,最后再说两点~
①如果你持有不同的看法,欢迎你在文章下方进行留言、评论。
②如果对你有帮助,或者你认可的话,欢迎给个小点赞,支持一下~
我是3Katrina,一个热爱编程的大三学生
(文章内容仅供学习参考,如有侵权,非常抱歉,请立即联系作者删除。)
作者:3Katrina
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。