腾讯 QQ 前端实习面经(一面)
发面经,攒人品!!!!
部门:QQ
时间线:
- 2024-03-01 一年前的简历被捞,遂约面
- 2024-03-07 一面
一面
- 实习经历与难点介绍
- 实习过程中的依赖升级是如何做的
1. (上一问延伸)npm 扁平安装机制如何处理版本冲突
在实习过程中进行依赖升级是一个常见的任务,通常可以按照以下步骤进行:
-
检查依赖更新:定期检查项目中的依赖是否有更新版本。可以通过查看项目的
package.json文件中的依赖列表,以及运行npm outdated命令来检查依赖的更新情况。 -
查看更新内容:在决定是否进行依赖升级之前,需要查看新版本的更新内容,了解新版本引入的改进、修复和可能的不兼容性。
-
备份当前依赖:在进行依赖升级之前,建议先备份当前的依赖状态,以防止升级后出现问题需要回退。
-
逐个升级依赖:对于每个需要升级的依赖,可以通过手动修改
package.json文件中的版本号,然后运行npm install命令来升级依赖。或者直接运行npm update <package-name>来升级指定的依赖包。 -
测试和验证:在进行依赖升级后,需要对项目进行测试和验证,确保升级后的依赖能够正常工作,并且不会引入新的问题或者不兼容性。
-
解决冲突:在进行依赖升级时,可能会出现依赖之间的版本冲突,此时需要根据实际情况解决冲突。npm采用的是扁平安装机制,即同一依赖包只会安装一次,但可能会存在不同版本的依赖包冲突的情况。可以通过手动调整依赖版本,或者使用npm提供的
npm dedupe命令来解决版本冲突问题。 -
持续监测:依赖升级是一个持续的过程,需要定期监测和更新项目中的依赖,以保持项目的安全性和稳定性。
总的来说,依赖升级是一个谨慎的过程,需要根据项目的实际情况和需求来进行决策,并且在升级过程中保持适当的测试和验证,以确保项目的稳定性和可靠性。 npm 使用的是扁平安装(Flat Install)机制,这意味着相同的依赖项在项目中只会安装一次,而不会重复安装。这种机制在处理版本冲突时可能会出现一些问题,但通常可以通过以下方法来解决:
-
版本锁定:在
package.json文件中明确指定每个依赖项的版本号,可以防止npm安装不同版本的相同依赖项。通过精确指定版本号,可以确保不会出现版本冲突。"dependencies": { "dependency-1": "1.2.3", "dependency-2": "^2.0.0" } -
依赖解决:npm会尝试解决依赖项的版本冲突,通常会选择安装符合所有依赖项的最新版本。在安装依赖时,npm会尽量满足项目中所有依赖项的版本需求,同时确保安装的依赖项不会相互冲突。
-
版本升级:如果发现存在版本冲突,可以尝试升级依赖项的版本来解决冲突。通过运行
npm update <package-name>命令可以将依赖项升级到符合项目需求的最新版本。 -
依赖清理:使用
npm prune命令可以清理项目中未被引用的依赖项,从而减少项目中不必要的依赖项,避免潜在的版本冲突。 -
手动解决:如果出现严重的版本冲突问题,可能需要手动调整依赖项的版本或者重新安装依赖项来解决冲突。可以根据具体情况逐个检查依赖项的版本,并进行调整或者重新安装。
综上所述,虽然npm的扁平安装机制可以减少依赖项的重复安装,但在处理版本冲突时仍然需要注意,并根据实际情况选择合适的解决方法。
3. package-lock.json 的作用
package-lock.json 文件是 npm 5+ 版本引入的一种锁定机制,用于确保项目依赖的安装过程在不同环境下始终保持一致性。它的作用包括:
-
确保版本一致性:
package-lock.json文件会记录当前项目依赖项的确切版本号及其依赖关系。这样,在不同的开发环境中安装依赖时,npm 可以根据该文件精确安装指定的版本,确保依赖项的版本一致性。 -
锁定依赖版本:当项目依赖项安装时,npm 会根据
package-lock.json文件中记录的版本信息来确定要安装的确切版本。这样可以避免在不同的开发环境中安装不同版本的依赖项,减少因版本差异导致的问题。 -
提高安装速度:由于
package-lock.json文件中记录了依赖项的版本信息,npm 在安装依赖时无需再进行版本解析和计算,可以直接根据文件中的记录安装指定版本的依赖,从而提高安装速度。 -
确保可重复性:
package-lock.json文件的存在可以确保项目的依赖安装过程具有可重复性。即使在不同的开发环境中执行npm install命令,由于依赖版本已经被锁定在package-lock.json中,因此安装的依赖版本也会保持一致。
总的来说,package-lock.json 文件可以确保项目的依赖安装过程稳定、可靠,并提高安装效率。它在 npm 项目中扮演着重要的角色,特别是在多人协作或部署到不同环境时,可以确保依赖的一致性和稳定性。
5. 类型体操:泛型函数
泛型函数是一种能够适用于多种数据类型的函数,它可以在函数定义时使用泛型类型来代替具体的数据类型。这样一来,函数就可以处理不同类型的参数,从而增加了函数的灵活性和通用性。
以下是一个简单的 TypeScript 泛型函数示例:
// 定义一个泛型函数,参数类型为 T,返回类型也为 T
function identity<T>(arg: T): T {
return arg;
}
// 使用泛型函数,传入不同类型的参数
let output1 = identity<string>("hello"); // 显式指定泛型类型为 string
console.log(output1); // 输出 "hello"
let output2 = identity<number>(123); // 显式指定泛型类型为 number
console.log(output2); // 输出 123
// 也可以让 TypeScript 根据参数类型推断泛型类型
let output3 = identity(true); // 自动推断泛型类型为 boolean
console.log(output3); // 输出 true
在上面的示例中,identity 函数使用了泛型类型 T,这样它就可以接受任意类型的参数,并返回相同类型的值。通过显式指定泛型类型或让 TypeScript 自动推断泛型类型,可以使函数在使用时更加灵活和方便。
泛型函数的优点在于可以编写更加通用、可复用的代码,同时能够提供类型安全性和代码提示,是 TypeScript 中非常常用的特性之一。
7. 算法:LRU 缓存(感谢牛友面经,刚好复习到了)
LRU(Least Recently Used)缓存是一种常见的缓存淘汰策略,其原理是根据数据访问的时间来淘汰最近最少使用的数据。具体实现可以使用哈希表和双向链表相结合的方式。
下面是一个简单的 JavaScript 实现:
class LRUCache {
constructor(capacity) {
this.capacity = capacity; // 缓存容量
this.cache = new Map(); // 使用 Map 存储数据
}
// 获取缓存中的数据
get(key) {
if (!this.cache.has(key)) {
return -1; // 如果缓存中没有对应的数据,则返回 -1
}
// 如果缓存中有对应的数据,则将其移动到 Map 的末尾表示最近使用过
const value = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, value);
return value;
}
// 向缓存中添加数据
put(key, value) {
if (this.cache.has(key)) {
// 如果缓存中已经有了这个 key,则删除原有的数据再添加新的数据
this.cache.delete(key);
} else if (this.cache.size >= this.capacity) {
// 如果缓存已满,则删除最久未使用的数据
const oldestKey = this.cache.keys().next().value; // 获取 Map 的第一个键
this.cache.delete(oldestKey);
}
// 将新的数据添加到 Map 的末尾表示最近使用过
this.cache.set(key, value);
}
}
// 示例使用
const cache = new LRUCache(2); // 创建容量为 2 的缓存
cache.put(1, 1); // 缓存中:{1=1}
cache.put(2, 2); // 缓存中:{1=1, 2=2}
console.log(cache.get(1)); // 返回 1,缓存中:{2=2, 1=1},1 已经被标记为最近使用过
cache.put(3, 3); // 缓存中:{3=3, 1=1},2 已经被淘汰
console.log(cache.get(2)); // 返回 -1(未找到)
cache.put(4, 4); // 缓存中:{4=4, 1=1},3 已经被淘汰
console.log(cache.get(1)); // 返回 1
console.log(cache.get(3)); // 返回 -1(未找到)
console.log(cache.get(4)); // 返回 4
在以上实现中,使用了 Map 数据结构来存储缓存数据,并在 get 方法中通过删除原有键值对再重新插入的方式,将最近使用过的数据移动到 Map 的末尾。同时,在 put 方法中,如果缓存已满则删除最久未使用的数据。
9. content-type 有哪些值, 分别代表什么?
Content-Type 是 HTTP 头部字段之一,用于指示请求或响应中的实体主体的媒体类型。常见的 Content-Type 值包括:
application/json:表示实体主体是 JSON 格式的数据。application/x-www-form-urlencoded:表示实体主体是经过 URL 编码的表单数据,通常用于 POST 请求中的表单提交。multipart/form-data:表示实体主体是一个包含多部分数据的表单,通常用于上传文件。text/plain:表示实体主体是纯文本格式。text/html:表示实体主体是 HTML 格式的文档。image/jpeg、image/png等:表示实体主体是图片格式的数据。audio/mpeg、audio/wav等:表示实体主体是音频格式的数据。video/mp4、video/quicktime等:表示实体主体是视频格式的数据。
这些是常见的 Content-Type 值,实际应用中可能还会有其他自定义的媒体类型。在 HTTP 请求和响应中,正确设置 Content-Type 是非常重要的,它能够确保客户端和服务器能够正确解析实体主体的数据格式。
作者:zbwer
链接:www.nowcoder.com/discuss/596…
来源:牛客网