今天一天三面,明天加油DW!!!
pdd终于终于HR面完了,许愿OC🎋🙏
收钱吧和滴滴都问的很细,基础及时回顾,特别是滴滴还穿插一些场景题目(不是很理解题意),DIDI一面B,收钱吧A-
滴滴面试官“可能”去掉口头禅,自信一点!!!
明天得物,加油,🎋🙏过!
大后天京东,更要加油!!!🙏🙏
1.Linux命令⏫部署(待总结)
2.!DocType:标准模式和怪异模式
3.唤端(的确不了解)
4.原型链,用嘴巴说出来,Function Object关系
5.JSONP手动实现
6.v-model并应用在模态框显示与隐藏上,如何实现
7.React能运行但出现性能优化的
你对这几个技术点感兴趣,我来为你梳理和解答。我会结合自己的知识,并参考一些可靠的搜索结果,力求详细清晰。
技术要点详解
1. Linux 命令与部署
Linux 命令是管理和部署服务器的基础。部署通常涉及系统更新、文件操作、服务管理和网络配置等。
核心部署命令
类别 | 命令示例 | 说明 |
---|---|---|
包管理 (Debian/Ubuntu) | sudo apt update && sudo apt upgrade | 更新软件包列表并升级已安装的包 |
sudo apt install <package_name> | 安装指定软件包 | |
包管理 (CentOS/RHEL) | sudo yum update | 更新软件包 |
sudo yum install <package_name> | 安装指定软件包 | |
文件操作 | mkdir <directory_name> | 创建目录 |
cp <source> <destination> | 复制文件或目录 | |
scp <local_file> user@remote_host:/remote/path | 安全地将文件复制到远程服务器 | |
rsync -avz <local_dir> user@remote_host:/remote_dir/ | 同步文件(高效增量复制) | |
服务管理 (systemd) | sudo systemctl start <service_name> | 启动服务 |
sudo systemctl stop <service_name> | 停止服务 | |
sudo systemctl enable <service_name> | 设置服务开机自启 | |
进程管理 | ps aux | 查看进程信息 |
kill <pid> 或 kill -9 <pid> | 终止进程(-9 用于强制终止) | |
top | 动态查看进程和系统资源使用情况 | |
网络相关 | ping <host> | 检查网络连通性 |
netstat -tuln | 查看监听中的端口 | |
curl <url> | 发送 HTTP 请求 |
部署流程建议
- 系统准备:更新系统,安装必要的工具(如
vim
,curl
,wget
)。 - 上传代码/应用:使用
scp
或rsync
将本地文件传输至服务器。 - 环境配置:安装运行时环境(如 Node.js, Python, JVM)。配置环境变量(如修改
~/.bashrc
或/etc/profile
)。 - 依赖安装:使用包管理器(如
npm install
,pip install
)安装应用依赖。 - 启动服务:
- 对于 Web 应用:可能需要配置并启动 Nginx (
sudo systemctl start nginx
) 或 Apache。 - 对于后台服务:可能需要配置守护进程(如使用
systemd
创建 service 文件)。
- 对于 Web 应用:可能需要配置并启动 Nginx (
- 防火墙与安全:配置防火墙(如
ufw
或iptables
)开放必要端口(如 80, 443)。 - 日志与监控:使用
tail -f <log_file>
实时查看日志,用top
或htop
监控资源。
2. DOCTYPE:标准模式与怪异模式
<!DOCTYPE>
声明位于 HTML 文档的最前面,用于告知浏览器使用何种文档类型定义(DTD)来解析和渲染文档。
模式区别
特性 | 标准模式 (Standards Mode) | 怪异模式 (Quirks Mode) |
---|---|---|
触发条件 | 包含正确且完整的 <!DOCTYPE> 声明 | 省略 <!DOCTYPE> 或 格式不正确/古老 |
渲染规则 | 遵循 W3C 标准 | 模拟 老式浏览器(如 IE5)的行为以实现向后兼容 |
盒模型 | 标准盒模型:width 和 height 指内容区域 | 怪异盒模型:width 和 height 包含内容、内边距和边框 |
布局和样式 | 行为可预测,跨浏览器一致性较高 | 行为怪异,不同浏览器差异可能很大 |
JavaScript | 浏览器以其支持的最高标准运行 | 可能使用兼容老版本的模式 |
常见 DOCTYPE 声明
- HTML5 (推荐):
<!DOCTYPE html>
- HTML 4.01 Strict:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
- HTML 4.01 Transitional:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
意义:始终使用正确的 <!DOCTYPE>
(推荐 HTML5)以触发标准模式,确保页面渲染的一致性、可预测性和跨浏览器兼容性。
3. 唤端技术
唤端(App Link)是指从 Web 页面(H5)或其他 App 中唤醒或跳转到另一个目标 App 的特定页面的技术。如果用户未安装目标 App,则引导用户到应用商店下载。
工作原理与方案
-
URL Scheme (最常用)
- 原理:App 在系统中注册一个自定义协议头(Scheme),例如
taobao://
。网页或其它 App 通过打开这个特定格式的 URL 来尝试唤醒 App。 - 示例:
<a href="weixin://">打开微信</a>
- 优点:兼容性好(iOS 和 Android 都支持)。
- 缺点:
- 无法准确判断是否唤醒成功(如果未安装,点击可能无反应或报错)。
- 在一些浏览器中会有弹窗确认,体验中断。
- 容易被 App 拦截(如微信中通常无法直接通过 Scheme 唤醒其他 App)。
- 有被劫持的风险(其他 App 注册了相同 Scheme)。
- 原理:App 在系统中注册一个自定义协议头(Scheme),例如
-
Universal Links (iOS) / App Links (Android)
- 原理:通过 标准的 HTTPS 链接 来唤醒 App。需要开发者在 App 和服务器端进行关联配置(如上传
apple-app-site-association
文件)。 - 优点:
- 无缝体验:无确认弹窗。如果用户安装了 App,直接唤醒;如果未安装,则直接打开该链接对应的 H5 页面,体验流畅。
- 不易被拦截(因为是 HTTPS 链接)。
- 缺点:配置相对复杂,且 需要用户主动点击(在 iOS 上,通过 JS 自动跳转通常无效)。
- 原理:通过 标准的 HTTPS 链接 来唤醒 App。需要开发者在 App 和服务器端进行关联配置(如上传
判断唤醒是否成功
由于 Web 端无法直接获得唤醒状态,通常采用一种 间接推测 的方法:
- 在触发唤醒(例如设置
iframe.src
或location.href
)的同时,启动一个计时器(例如 2.5 秒)。 - 监听页面的
blur
或visibilitychange
事件。因为如果唤醒成功,当前 H5 页面会切换到后台,会触发这些事件。 - 如果在计时器超时前触发了这些事件且
document.hidden
为true
,就推测为唤醒成功。 - 如果计时器超时,则判断为唤醒失败,执行降级方案(如跳转到应用商店或下载页)。
let timer = setTimeout(() => {// 唤醒失败,跳转应用商店window.location.href = 'https://apps.apple.com/app/id123456'; // iOS 商店地址
}, 2500);const successHandler = () => {if (document.hidden) {clearTimeout(timer); // 清除超时定时器}
};window.addEventListener('blur', successHandler, { once: true });
window.addEventListener('visibilitychange', successHandler, { once: true });// 触发唤端 (以 iframe 方式为例)
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = 'myapp://detail/123';
document.body.appendChild(iframe);
4. 原型链 & Function/Object 关系
用“嘴巴说出来”的方式解释:
原型链 (Prototype Chain) 是 JavaScript 中实现继承和共享属性的主要机制。每个对象(Object
)都有一个内部属性 [[Prototype]]
(在大多数浏览器中可通过 __proto__
访问),它指向另一个对象,即它的原型。当你试图访问一个对象的属性时,如果该对象自身没有这个属性,JavaScript 引擎就会去它的原型对象上找,如果原型对象上也没有,就继续去原型对象的原型上找,这样一层层向上追溯,直到找到该属性或到达链条的尽头(null
)。这条链状的追溯关系就是原型链。
Function 和 Object 的关系(这是理解原型链的关键):
Function
和Object
都是函数,而函数也是对象。Object.prototype
是几乎所有对象的原型链终点(其__proto__
是null
)。Function.prototype
是所有函数的原型(包括Object
和Function
自身)。Object.__proto__ === Function.prototype
(因为Object
是个构造函数,是函数)Function.__proto__ === Function.prototype
(Function
自身也是函数)
Function.prototype
本身也是一个对象,它的__proto__
指向Object.prototype
。Function.prototype.__proto__ === Object.prototype
这就形成了一个“循环”但非常自洽的关系:
- 对象继承自
Object.prototype
。 - 函数继承自
Function.prototype
。 Function.prototype
本身作为一个对象,又继承自Object.prototype
。
你可以用这段代码验证它们的关系:
console.log(Function.__proto__ === Function.prototype); // true
console.log(Object.__proto__ === Function.prototype); // true
console.log(Function.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
5. JSONP 手动实现
JSONP (JSON with Padding) 是一种利用 <script>
标签没有跨域限制的特性来实现跨域数据请求的技巧。
实现步骤
- 前端定义全局回调函数:在全局作用域(
window
)上定义一个函数,用于接收数据。 - 动态创建
<script>
标签:其src
指向目标 API 的 URL,并在 URL 中通过查询参数(如callback=functionName
)告诉服务器需要调用的回调函数名。 - 服务器响应:服务器将数据用该回调函数名包裹(即“Padding”)后返回,例如
callbackFunction({ "data": "value" })
。 - 自动执行:返回的脚本内容会被浏览器立即执行,从而调用前端预先定义好的回调函数,并传入数据。
- 清理:在回调函数中移除之前创建的
<script>
标签。
<!-- 前端实现 -->
<script>function handleJSONPResponse(data) {// 处理从跨域请求获取的数据console.log('Received data:', data);// 清理:移除script标签 (可选,但建议做)document.getElementById('jsonpScript').remove();}// 动态创建script标签并发起请求const script = document.createElement('script');script.id = 'jsonpScript';script.src = 'https://api.example.com/data?callback=handleJSONPResponse';document.body.appendChild(script);
</script>
// 服务器端 (Node.js 示例)
const http = require('http');
const url = require('url');const server = http.createServer((req, res) => {const parsedUrl = url.parse(req.url, true);const callbackName = parsedUrl.query.callback;const data = { message: 'Hello from JSONP!' };if (callbackName) {// 设置Content-Type为JavaScriptres.writeHead(200, { 'Content-Type': 'application/javascript' });// 返回用回调函数包裹的JSON数据res.end(`${callbackName}(${JSON.stringify(data)})`);} else {res.end(JSON.stringify(data));}
});server.listen(3000);
缺点:JSONP 只支持 GET 请求,不安全(容易受到 XSS 攻击),并且需要服务器端配合。
6. v-model 与模态框
Vue.js 中的 v-model
是一个语法糖,它本质上是双向数据绑定的简化写法。它通常用于表单元素(如 input
, checkbox
, select
),默认情况下相当于 :value
和 @input
的组合。
<input v-model="message">
<!-- 等价于 -->
<input :value="message" @input="message = $event.target.value">
在模态框显示与隐藏上的应用
模态框(Modal)的显示和隐藏通常由一个布尔值数据控制(例如 isModalVisible
)。我们可以利用 v-model
来简化父组件与模态框子组件之间的通信。
1. 父组件 (ParentComponent.vue)
<template><div><button @click="showModal = true">打开模态框</button><!-- 使用 v-model 绑定到 isModalVisible 变量 --><Modal v-model="isModalVisible" /><!-- 等价于 --><!-- <Modal :value="isModalVisible" @input="isModalVisible = $event" /> --></div>
</template><script>
import Modal from './Modal.vue';export default {components: { Modal },data() {return {isModalVisible: false};}
};
</script>
2. 子组件模态框 (Modal.vue)
<template><div class="modal-overlay" v-if="value" @click.self="closeModal"><div class="modal-content"><h2>模态框标题</h2><p>这是模态框的内容...</p><button @click="closeModal">关闭</button></div></div>
</template><script>
export default {props: ['value'], // 接收 v-model 传来的 valuemethods: {closeModal() {// 发出 input 事件并传递新值,以更新父组件中的 v-model 绑定值this.$emit('input', false);}}
};
</script><style scoped>
.modal-overlay {position: fixed;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(0, 0, 0, 0.5);display: flex;justify-content: center;align-items: center;
}
.modal-content {background: white;padding: 2rem;border-radius: 8px;
}
</style>
关键点:
- 子组件接收一个名为
value
的 prop。 - 当子组件需要关闭自己时(如点击遮罩层或关闭按钮),它发出一个
input
事件,并传递新的值(通常是false
)。 - 父组件中
v-model
绑定的变量(isModalVisible
)会被子组件发出的input
事件更新,从而控制模态框的显示状态。
7. React 性能优化(能运行但需优化)
React 应用能运行但性能不佳,常见原因和优化方向:
-
不必要的组件重新渲染:这是最常见的性能问题。
- 原因:父组件重新渲染会导致所有子组件默认重新渲染,即使其 props 未变。
- 优化:
- 使用
React.memo
:对函数组件进行记忆化,防止在 props 浅比较未变化时重新渲染。
const MyComponent = React.memo(function MyComponent({ name }) {return <div>{name}</div>; });
- 使用
useMemo
:记忆化昂贵的计算结果,避免在每次渲染时都重新计算。
const expensiveValue = useMemo(() => {return calculateExpensiveValue(a, b); }, [a, b]); // 依赖项变化时才重新计算
- 使用
useCallback
:记忆化回调函数,防止因为函数引用变化导致依赖该函数的子组件不必要的重渲染。
const handleClick = useCallback(() => {doSomething(a, b); }, [a, b]); // 依赖项变化时才会创建新函数
- 使用
-
状态结构不合理:状态放置的位置太高,导致更新时范围过大。
- 优化:状态下放。将状态移动到尽可能靠近需要使用的组件。或者使用 Context API 时,将不同领域的状态分离到多个 Context 中,避免无关更新。
-
大型列表渲染:一次性渲染成百上千条列表项。
- 优化:使用虚拟化列表(Windowning),如
react-window
或react-virtualized
库。只渲染可视区域内的列表项,极大提升性能。
- 优化:使用虚拟化列表(Windowning),如
-
巨大的 JavaScript 包体积:导致应用首次加载缓慢。
- 优化:
- 代码分割 (Code Splitting):使用
React.lazy
和Suspense
进行路由级或组件级的懒加载。
const LazyComponent = React.lazy(() => import('./LazyComponent')); function MyComponent() {return (<Suspense fallback={<div>Loading...</div>}><LazyComponent /></Suspense>); }
- 分析并优化 Bundle,使用工具 like Webpack Bundle Analyzer。
- 代码分割 (Code Splitting):使用
- 优化:
-
副作用滥用或错误使用依赖项:在
useEffect
中执行了昂贵操作或依赖项数组设置不正确。- 优化:确保
useEffect
的依赖项数组包含所有Effect内部使用的、且会随时间变化的变量。避免在Effect中做不需要的重复工作。
- 优化:确保
-
单个组件逻辑过于复杂:一个组件做了太多事情,导致内部状态和逻辑复杂,容易引发渲染问题。
- 优化:拆分组件的逻辑。可以使用自定义 Hook 来分离和复用状态逻辑。
要定位具体性能瓶颈,强烈推荐使用 React DevTools Profiler 来分析组件的渲染时间和渲染原因。