2023.03.29 - 2023.04.02 更新前端面试问题总结(7道题)
获取更多面试问题可以访问
github 地址: github.com/pro-collect…
gitee 地址: gitee.com/yanleweb/in…
目录:
-
中级开发者相关问题【共计 2 道题】
- 240.[Redux] 的存储过程【web框架】【出题公司: 腾讯】
- 245.react 中是如何实现 下拉菜单场景, 点击区域外关闭下拉组件?【web应用场景】【出题公司: 百度】
-
高级开发者相关问题【共计 4 道题】
- 238.如何保证用户的使用体验【web应用场景】【出题公司: 腾讯】
- 239.如何在前端团队快速落地代码规范【工程化】【出题公司: 腾讯】
- 241.[Redux] 简单实现一下核心源码【web框架】【出题公司: 腾讯】
- 243.[webpack] webpack 是如何给 web 应用注入环境变量的, 原理是啥【工程化】【出题公司: 百度】
-
资深开发者相关问题【共计 1 道题】
- 242.[Redux] react-redux 是如何更新到 UI 的, 写一下这部分的核心源码【web框架】【出题公司: 腾讯】
中级开发者相关问题【共计 2 道题】
240.[Redux] 的存储过程【web框架】【出题公司: 腾讯】
Redux 的存储过程可以简单地分为以下几个步骤:
- Action Creator 函数被调用,生成一个 Action 对象;
- Action 对象被传递给 Store.dispatch() 方法;
- Redux Store 调用 Reducer 函数,将当前的 State 和 Action 作为参数传入;
- Reducer 函数根据 Action 的类型,生成一个新的 State;
- Redux Store 将新的 State 存储下来,用于下一次的状态更新;
- 组件通过调用 Store.subscribe() 方法,监听 Store 中 State 的变化;
- 当 State 发生变化时,Store 会通知所有的订阅者,订阅者会重新渲染相应的组件。
这个过程可以简单地描述为:Action -> Reducer -> Store -> View。其中,Action 是一个纯对象,它描述了发生的事件;Reducer 是一个纯函数,它接收当前的 State 和 Action,返回一个新的 State;Store 是将 Action 和 Reducer 结合起来的对象,它维护了应用程序的 State;View 则是 React 组件,它通过 Store.subscribe() 方法监听 State 的变化,根据 State 的变化重新渲染页面。
245.react 中是如何实现 下拉菜单场景, 点击区域外关闭下拉组件?【web应用场景】【出题公司: 百度】
在 React 中,要实现点击区域外关闭下拉组件,一般可以使用以下几种方法:
- 在下拉组件的根元素上监听点击事件,当点击区域不在下拉组件内时,触发关闭下拉组件的操作。这可以通过添加全局点击事件,然后在事件处理程序中判断点击区域是否在下拉组件内来实现。具体实现如下:
import React, { useRef, useEffect } from 'react';
function DropdownMenu(props) {
const menuRef = useRef(null);
useEffect(() => {
function handleClickOutside(event) {
if (menuRef.current && !menuRef.current.contains(event.target)) {
props.onClose();
}
}
document.addEventListener('click', handleClickOutside);
return () => {
document.removeEventListener('click', handleClickOutside);
};
}, [props]);
return (
<div ref={menuRef}>
{/* 下拉菜单内容 */}
</div>
);
}
- 在下拉组件的父元素上监听点击事件,当点击区域不在下拉组件及其父元素内时,触发关闭下拉组件的操作。具体实现如下:
import React, { useState } from 'react';
function Dropdown(props) {
const [isOpen, setIsOpen] = useState(false);
function toggleDropdown() {
setIsOpen(!isOpen);
}
function handleClickOutside(event) {
if (!event.target.closest('.dropdown')) {
setIsOpen(false);
}
}
return (
<div className="dropdown" onClick={handleClickOutside}>
<button onClick={toggleDropdown}>Toggle Dropdown</button>
{isOpen && <DropdownMenu onClose={() => setIsOpen(false)} />}
</div>
);
}
在上述代码中,我们在 Dropdown 组件的根元素上添加了点击事件处理程序 handleClickOutside,当点击区域不在 .dropdown 元素内时,触发关闭下拉组件的操作。由于 DropdownMenu 组件位于 Dropdown 组件内部,因此当点击下拉菜单时,事件会冒泡到 Dropdown 组件,从而不会触发关闭操作。
- 除了上述方法外,还可以使用
useRef钩子来监听鼠标点击事件。具体实现可以在下拉组件的根元素上使用ref属性来获取 DOM 元素的引用,然后在组件挂载时使用addEventListener方法绑定mousedown事件,最后在事件处理函数中判断鼠标点击的位置是否在下拉组件内,如果不在,则关闭下拉组件。
示例代码如下:
import { useRef, useState, useEffect } from 'react';
function Dropdown() {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef(null);
useEffect(() => {
function handleClickOutside(event) {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setIsOpen(false);
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [dropdownRef]);
return (
<div ref={dropdownRef}>
<button onClick={() => setIsOpen(!isOpen)}>Toggle Dropdown</button>
{isOpen && (
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
)}
</div>
);
}
这种方法可以在组件内部处理点击事件,不需要将事件处理函数传递给父组件。但是相对而言代码会比较繁琐,需要手动处理事件绑定和解绑。
高级开发者相关问题【共计 4 道题】
238.如何保证用户的使用体验【web应用场景】【出题公司: 腾讯】
【如何保证用户的使用体验】这个也是一个较为复杂的话题, 这个也不是问题了, 这个算是话题吧;
主要从以下几个方面思考问题:
- 性能方向的思考
- 用户线上问题反馈,线上 on call 的思考
- 用户使用体验的思考, 交互体验使用方向
- 提升用户能效方向思考
239.如何在前端团队快速落地代码规范【工程化】【出题公司: 腾讯】
// todo 待整理
241.[Redux] 简单实现一下核心源码【web框架】【出题公司: 腾讯】
实现 Redux 的源码主要包括以下几个步骤:
- 实现 createStore 函数,创建 store 对象,该函数接收一个 reducer 函数作为参数,返回一个对象。
- 在 createStore 函数内部,定义一个 state 变量来存储当前的状态值,定义一个 listeners 数组来存储所有的监听函数。
- 实现 getState 方法,返回当前的状态值。
- 实现 dispatch 方法,接收一个 action 对象作为参数,将当前的状态值和 action 对象传给 reducer 函数,更新状态值。然后遍历 listeners 数组,调用所有的监听函数。
- 实现 subscribe 方法,接收一个监听函数作为参数,将该函数添加到 listeners 数组中,以便在状态更新时调用。
- 实现 combineReducers 函数,将多个 reducer 函数合并成一个 reducer 函数。
- 在 createStore 函数内部,将传入的 reducer 函数或者合并后的 reducer 函数赋值给一个内部的 currentReducer 变量。
- 在 dispatch 方法内部,将 currentReducer 赋值给一个局部变量,以保证在 reducer 函数中调用 dispatch 方法时可以获取到最新的 reducer 函数。
下面是代码实现:
// 实现 createStore 函数
function createStore(reducer) {
let state;
const listeners = [];
function getState() {
return state;
}
function dispatch(action) {
state = reducer(state, action);
for (let i = 0; i < listeners.length; i++) {
listeners[i]();
}
}
function subscribe(listener) {
listeners.push(listener);
}
dispatch({});
return {
getState,
dispatch,
subscribe
};
}
// 实现 combineReducers 函数
function combineReducers(reducers) {
return function(state = {}, action) {
const nextState = {};
for (const key in reducers) {
nextState[key] = reducers[key](state[key], action);
}
return nextState;
};
}
在使用时,可以先定义 reducer 函数:
function todos(state = [], action) {
switch (action.type) {
case "ADD_TODO":
return [
...state,
{
id: action.id,
text: action.text,
completed: false
}
];
case "TOGGLE_TODO":
return state.map(todo =>
todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
);
default:
return state;
}
}
function visibilityFilter(state = "SHOW_ALL", action) {
switch (action.type) {
case "SET_VISIBILITY_FILTER":
return action.filter;
default:
return state;
}
}
然后将它们传入 combineReducers 函数,创建一个 reducer 函数:
const reducer = combineReducers({
todos,
visibilityFilter
});
最后调用 createStore 函数,创建一个 store 对象:
const store = createStore(reducer);
现在就可以使用 store 对象来获取状态值、派发 action、监听状态变化了。
可以参考文档: juejin.cn/post/684490…
243.[webpack] webpack 是如何给 web 应用注入环境变量的, 原理是啥【工程化】【出题公司: 百度】
Webpack 可以通过 DefinePlugin 插件给 web 应用注入环境变量。该插件会在编译过程中替换掉代码中指定的变量,以实现在运行时替换成环境变量的值。
在 webpack 的配置文件中,需要先引入该插件,然后将需要注入的环境变量通过该插件进行配置。例如:
const webpack = require('webpack');
module.exports = {
// 其他配置
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
},
API_URL: JSON.stringify('http://api.example.com')
})
]
};
上述配置中,定义了两个需要注入的变量,分别是 process.env.NODE_ENV 和 API_URL。其中,process.env.NODE_ENV 是一个常用的环境变量,用来标识当前是开发环境还是生产环境;API_URL 是一个自定义的环境变量,用来存储 API 的地址。
在代码中使用这些环境变量时,只需要直接引用即可:
if (process.env.NODE_ENV === 'production') {
console.log('当前为生产环境');
}
fetch(API_URL + '/users')
.then(response => response.json())
.then(data => console.log(data));
Webpack 在编译时会将这些变量替换成对应的值,例如:
if ('production' === 'production') {
console.log('当前为生产环境');
}
fetch('http://api.example.com' + '/users')
.then(response => response.json())
.then(data => console.log(data));
通过这种方式,我们就可以在代码中方便地使用环境变量,同时保证了在不同环境下都能正确地使用相应的变量值。
资深开发者相关问题【共计 1 道题】
242.[Redux] react-redux 是如何更新到 UI 的, 写一下这部分的核心源码【web框架】【出题公司: 腾讯】
react-redux 和 redux 的关系
Redux 和 React-Redux 是两个独立的库,但它们通常一起使用,因为 Redux 库本身并不针对 React,而是一个通用的状态管理库,而 React-Redux 则是一个用于将 Redux 集成到 React 应用程序中的库。
React-Redux 提供了一组 React 组件和钩子,使得在 React 应用程序中使用 Redux 变得更加容易。它提供了一个 Provider 组件,可以将 Redux store 注入到整个 React 应用程序中,并且可以使用 connect 函数将组件连接到 Redux store,使它们可以访问和修改 store 中的数据。
使用 React-Redux,我们可以将 Redux 的状态管理能力与 React 的组件化能力结合起来,使得应用程序的状态可以很方便地被管理和共享,并且组件也可以方便地访问和修改应用程序的状态。
react-redux 是如何集成到 UI 的?
react-redux 提供了两个主要的组件 Provider 和 connect,它们用于将 Redux 状态管理与 React 组件相结合。
首先,使用 Provider 组件将 Redux store 传递给整个应用程序。可以将 <Provider> 组件作为最高层的组件,这样在应用程序中的所有组件中都可以访问到 Redux store。
下一步,使用 connect 函数连接 Redux store 和组件。connect 函数是一个高阶函数,它接收两个参数:mapStateToProps 和 mapDispatchToProps,并返回另一个函数,这个函数接受一个组件作为参数,并返回一个增强版的组件。
mapStateToProps 函数用于从 Redux store 中获取需要的 state 数据,并将其映射到组件的 props 上。mapDispatchToProps 函数用于将 action creator 映射到组件的 props 上,这样组件就可以直接调用 action creator 发起 action,而不需要手动分发 dispatch。
使用 connect 函数生成的增强版组件可以访问到 Redux store 中的 state 和 dispatch,并将它们作为 props 传递给原始组件。在组件中,可以直接使用这些 props 来获取和更新 state,以及发起 action。当组件中的 state 或 props 发生变化时,connect 函数会自动更新组件,以反映最新的 state 和 props。
通过这种方式,react-redux 让我们可以在 React 组件中使用 Redux 进行状态管理,实现了 Redux 和 React 的无缝集成。
简单写一下更新 UI 核心代码实现
react-redux 是基于 React 和 Redux 的,主要用于将 Redux 的状态管理功能集成到 React 应用程序中。它主要包括两个部分:Provider 和 connect。
Provider 组件是 react-redux 的核心,它将 Redux 的 store 作为 props 传递给 React 组件,并通过 React 的上下文(Context)使得后代组件能够访问到 store。
connect 函数用于连接 React 组件与 Redux store,返回一个新的组件。该函数的主要作用是在组件中提供 mapStateToProps 和 mapDispatchToProps 函数,从而使组件能够从 Redux store 中读取数据,并向 store 分发 action。
下面是一个简单的实现,用于说明 react-redux 是如何集成到 UI 的:
// Provider.js
import React from 'react';
import PropTypes from 'prop-types';
export const StoreContext = React.createContext();
export default function Provider(props) {
const { store, children } = props;
return (
<StoreContext.Provider value={store}>
{children}
</StoreContext.Provider>
);
}
Provider.propTypes = {
store: PropTypes.object.isRequired,
children: PropTypes.any,
};
// connect.js
import React from 'react';
import PropTypes from 'prop-types';
import { StoreContext } from './Provider';
export default function connect(mapStateToProps, mapDispatchToProps) {
return function wrapWithConnect(WrappedComponent) {
class Connect extends React.Component {
componentDidMount() {
const { store } = this.context;
this.unsubscribe = store.subscribe(this.handleChange.bind(this));
}
componentWillUnmount() {
this.unsubscribe();
}
handleChange() {
this.forceUpdate();
}
render() {
const { store } = this.context;
const props = {
...this.props,
...mapStateToProps(store.getState(), this.props),
...mapDispatchToProps(store.dispatch, this.props),
};
return <WrappedComponent {...props} />;
}
}
Connect.contextType = StoreContext;
Connect.propTypes = {
store: PropTypes.object,
};
Connect.displayName = `Connect(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;
return Connect;
};
}
这里的 Provider 组件用于将 Redux 的 store 传递给 React 组件:
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import App from './App';
import rootReducer from './reducers';
const store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
而 connect 函数用于将 React 组件连接到 Redux store:
import React from 'react';
import { connect } from 'react-redux';
import { increment } from './actions';
function Counter(props) {
const { count, increment } = props;
return (
<div>
<p>Count: {count}</p>
<button onClick={() => increment()}>+</button>
</div>
);
}
const mapStateToProps = state => {
return {
count: state.count,
};
};
const mapDispatchToProps = dispatch => {
return {
increment: () => dispatch(increment()),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Counter);