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()則是延時執行。