前端面试准备-4
1.React Router的history模式中,push和replace有什么区别
都是用于页面导航,但是他们对浏览器历史记录的处理不一样。
①:push是在浏览历史栈里加入一条新的浏览历史,点击返回键会返回上一个页面
②;replace是替换当前历史记录,点击回退键,会回到替换前页面
// 使用 push 方法导航
navigate('/home');
history.push('/home');// 使用 replace 方法导航
navigate('/home', { replace: true });
history.replace('/home');
2.React中,除了在构造函数中绑定this,其它绑定的方法有哪些
①:使用箭头函数定义类方法
②:在render方法中使用箭头函数
③:使用bind方法在render中绑定
3.为什么在React中遍历时不建议使用索引作为唯一的key
因为当数组顺序发生变化,或发生增加、删除等,会导致不必要的重新渲染。
3.ReactRouter中的router组件有几种类型
①:BrowserRouter
②:HashRouter,使用url的hash部分(#)来实现路由
③:MemoryRouter,将历史记录保存在内存中
4.在React的render函数中是否可以直接写if-else判断
不能。因为render函数返回的时JSX,本质上时JavaScript表达式,在表达式内部不能直接写于语句。
可以使用三元运算符或逻辑与运算符。
//三元运算符
render() {return (<div>{this.state.isLoggedIn ? '欢迎回来' : '请登录'}</div>)
}//逻辑运算
render() {return (<div>{this.state.isLoggedIn && '欢迎回来'}</div>)
}
5.如何在React项目中导入图片,那种效果更好
①:import导入,适用于项目文件内的静态图片资源
import logo from './images/logo.png'function Header() {return <img src={logo} alt="logo" />
}
②:request方法,适用于动态导入图片
function Avatar() {const avatar = require('./images/avatar.png')return <img src={avatar} alt="avatar" />
}
③:public文件夹,适用于不需要经过打包处理的静态图片资源
function Banner() {return <img src="/images/banner.png" alt="banner" />
}
6.在React的JSX中,属性是否可以被覆盖,覆盖原则是什么
①:从左到右覆盖,后面的同名属性会覆盖前面的同名属性
②:展开运算符的覆盖规则。使用展开运算符(...)传递props时,展开运算符后面的属性会覆盖展开运算符里面的同名属性
③:显示属性优先。显示声明的属性会覆盖展开运算符中的属性
// 默认样式
const defaultProps = {className: 'btn',type: 'button'
};// 使用时覆盖默认值
<button {...defaultProps} className="btn-primary" />
// 最终 className 为 "btn-primary"
7.什么是React中的受控组件,它的应用场景是什么
受控组件是指表单元素的值受React state控制的组件。在受控组件中,表单数据由React组件处理,而不是由DOM本身处理。
实现关键点:
①:将表单元素的值与state绑定
const [value, setValue] = useState('');
<input value={value} onChange={e => setValue(e.target.value)} />
②:提供onchange事件处理函数
③:表单元素的值始终等于state中的值
import { useState } from 'react';function MyInput() {const [value, setValue] = useState('');const handleChange = (e) => {setValue(e.target.value);};return (<input type="text" value={value} onChange={handleChange} />);
}
8.为什么React使用虚拟DOM来提高性能
直接操作真实dom的开销大,相对昂贵和耗时。虚拟DOM是一种轻量级副本,允许React在内存中进行计算和差异检测,然后将最小的、最高效的变化应用到真实dom上。这样可以减少不必要的真实DOM跟新,提高性能。
9.Node.js中同步和异步代码的区别
主要在于代码的执行顺序和阻塞行为。
①:同步代码。执行后会阻塞后续代码的执行,直到当前操作完成。
②:异步代码。不会阻塞后续代码的执行。异步操作会在完成时,通过回调函数、Promise以及async/await等机制通知相关的代码片段去处理。
// 同步代码
const fs = require('fs');
const data = fs.readFileSync('file.txt', 'utf8');
console.log(data); // 此时,代码会等待文件读取完成再执行后面的代码
console.log('Done'); // 这行代码会在文件读取完成后执行// 异步代码
fs.readFile('file.txt', 'utf8', (err, data) => {if (err) throw err;console.log(data); // 文件读取完成时,这个回调函数才会被执行
});
console.log('Done'); // 这行代码会被立即执行,不会等待文件读取完成
10.Node.js中的Buffer对象是什么,作用是什么?
Buffer对象是Node.js中的全局类,用来在处理二进制数据时,提供对内存缓冲区的操作。可以非常有效的处理非字符串类型的数据,如从文件中读取的二进制数据或者网络协议传输的数据。
作用:
- 处理二进制数据:例如视频、文件、图片的读取
- 与流结合:与Node.js的流操作结合,通常用于文件处理和网络传输
- 转换编码格式:utf8,base64等转码
具体使用
①:创建buffer
// 分配 10 个字节的 Buffer
const buf1 = Buffer.alloc(10);// 通过字符串创建,默认编码为 'utf8'
const buf2 = Buffer.from('Hello, World!');
②:读写操作
const buf = Buffer.alloc(10);
buf.write('Hello');// 输出部分写入后的结果
console.log(buf.toString('utf8', 0, 5)); // Hello
③:与流结合
const fs = require('fs');
const readStream = fs.createReadStream('example.txt');
readStream.on('data', (chunk) => {console.log(`Received ${chunk.length} bytes of data.`);
});
④:编码转换
const buf = Buffer.from('Hello, World!');
console.log(buf.toString('base64')); // 输出 base64 编码的字符串
11.Node.js中的process对象是什么,常用的属性有哪些
在 Node.js 中,process
是一个 全局对象,提供了当前 Node.js 进程的信息与控制方式,不需要require引入。它是 Node.js 与操作系统交互的桥梁,允许你访问环境变量、参数、内存使用情况、退出程序等。
名称 | 作用 |
---|---|
process.argv | 获取命令行参数 |
process.env | 获取环境变量 |
process.exit([code]) | 退出程序 |
process.cwd() | 当前工作目录 |
process.pid | 当前进程 ID |
process.platform | 当前操作系统平台 |
process.memoryUsage() | 获取内存使用信息 |
process.nextTick() | 注册微任务(在事件循环前执行) |
12.Node.js中的require和import有什么区别
①:require
require
是 CommonJS 的模块引入方式,Node.js 从一开始就使用它;
语法形式为:const module = require( 'module_name' )
require通常用于需要立即同步加载模块的情况,因为他是同步的
②:import
import
是 ES6 模块系统(ESM) 的语法,是浏览器和现代 JavaScript 的标准模块系统。
语法为 import module from 'module_name'
import更适合现代前端项目和需要异步加载模块的场景,因为他是异步加载的,不会阻塞主线程。
13.Node.js的回调、Promise和async/await有什么区别
皆为Node.js处理异步操作的三种方式
①:回调
这种方法需要将函数作为参数传递给另一个函数,并在异步操作完成后调用这个回调函数。
(当一个函数作为参数传入另一个参数中,并且它不会立即执行,只有当满足一定条件后该函数才可以执行,这种函数就称为回调函数。我们熟悉的定时器和Ajax中就存在有回调函数)
容易造成“回调地狱”
//想要打印1 2 3,就得如下的代码:setTimeout(function () { //第一层console.log('1');setTimeout(function () { //第二程console.log('2');setTimeout(function () { //第三层console.log('3');}, 1000)}, 2000)}, 3000)//这种回调函数里面嵌套回调函数就叫回调地狱
②:Promise
对回调的一种改进,更现代化的异步处理方式。它表示一个未来将完成的异步操作或一个错误操作。其中,Promise可以链式调用,解决了回调地狱的问题
const promise = new Promise((resolve, reject) => {setTimeout(() => {resolve('Success!');}, 1000);
});
promise.then(result => console.log(result)).catch(error => console.error(error));
③:async/await
async/await是基于Promise的语法糖,让异步代码看起来更像是同步代码。可以使用try/catch处理错误。
async function fetchData() {try {const data = await fs.promises.readFile('example.txt', 'utf8');console.log(data);} catch (err) {console.error(err);}
}
fetchData();
14.Node.js中的定时器函数setImmediate()和setTimeout()函数有什么区别
都是用来调度异步任务的定时器函数
①:setImmediate()允许在当前事件循环结束后立即执行函数,而setTimeout()则是在指定时间后执行回调函数
②:在I/O操作完成后,setImmediate()的回调函数通常会比setTimeout()的回调函数优先执行。
③:setImmediate()主要是用于希望在I/O执行完后立即执行,而setTimeout()则是延时执行。