廢話少說渤昌,本文分四個部分虽抄,css、js独柑、知識點一、知識點二私植、React(部分問題沒有給出答案忌栅,后續(xù)更新)
css面試問題
一、垂直居中問題
https://www.cnblogs.com/clj2017/p/9293363.html
1曲稼、設(shè)置行高
2索绪、彈性布局(父元素設(shè)置display:flex;子元素設(shè)置align-slef:center)
3、偽元素
父元素設(shè)置:before
content:“”贫悄;
display:inline-block;
vertical-align:middle;
height:100%;
4:父元素設(shè)置display:table
子元素設(shè)置display:table-cell;
vertical-align:middle;
二瑞驱、彈性布局
http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
容器屬性、項目屬性
1窄坦、容器屬性
flex-direction:row | row-reverse | column? | column-reverse
決定項目的排列順序
flex-wrap:wrap | nowrap | wrap-reverse
是否換行
flex-flow:<flex-direction> | <flex-wrap>
flex-direction和flex-wrap簡寫形式
justify-content:flex-start | flex-end | center | space-between | space-around
項目在主軸上的對齊方式
align-items:flex-start | flex-end | center | baseline | stretch
項目在交叉軸的對齊方式
align-content:flex-start | flex-end | center | stretch | space-between | space-around
定義了多跟軸線的對齊方式 唤反,如果項目只有一根軸線,該屬性不起作用鸭津。
2彤侍、項目屬性
order
定義項目的排列順序,值越小排列越靠前逆趋,默認(rèn)為0.
flex-grow
定義項目的放大比例盏阶,默認(rèn)為0,即如果存在剩余空間也不放大
如果所有項目的flex-grow都為1闻书,等分剩余空間名斟。如果一個項目的flex-grow為2,其他項目的flex-grow都為1魄眉,前者占用的剩余空間將比其他項多一倍砰盐。
flex-shrink
定義項目的縮小比例,默認(rèn)為1杆融,即如果空間不足楞卡,該項目將縮小
flex-basis
分配多余空間之前項目占據(jù)的主軸空間
flex
flex-grow | flex-shrink | flex-basis的簡寫。
align-self:auto | flex-start | flex-end | center | baseline | stretch
單個項目在交叉的對齊方式,可與其他項目不一樣
三蒋腮、BFC
https://blog.csdn.net/sinat_36422236/article/details/88763187
1淘捡、定義:塊級格式化上下文
2、觸發(fā)BFC的條件
⑴浮動
⑵position:absolute fixed
⑶display:inline-block | table-cell | flex |
⑷overflow:hidden | scroll | auto
3池摧、BFC解決的問題
(1)避免margin重疊
(2)解決浮動重疊
(3)解決高度塌陷問題
四焦除、清除浮動的方式
清除浮動主要是為了解決父級元素因為子級浮動引起的內(nèi)部高度為0的問題。
1作彤、額外標(biāo)簽
在父元素下寫一個標(biāo)簽:用clear:both
2膘魄、overflow:hidden;觸發(fā)bfc
3竭讳、偽元素:after{clear:both;content:"";display:block;}
js
一创葡、解決浮點數(shù)計算問題
const floatAdd = (arg1, arg2) => {
? var r1, r2, m;
? r1 = arg1.toString().split(".")[1].length;
? r2 = arg2.toString().split(".")[1].length;
? m = Math.pow(10, Math.max(r1, r2));
? var rs = (arg1 * m + arg2 * m) / m;
? console.log(rs);
? return rs;
};
二、數(shù)組扁平化
1绢慢、遞歸
2灿渴、轉(zhuǎn)化為字符串
var rs = [1, 2, 3, [4, 5, [8, 78], 6]]
? .toString()
? .split(",")
? .map(item => {
? ? return Number(item);
? });
console.log(rs);
三、兩個數(shù)組求交集
function intersection(arr1,arr2){
return arr1.filter(item=>{
if(arr2.indexOf(item)>-1){
return item
}
})
}
四胰舆、數(shù)組去重
var arr2 = [2, 1, 3, 1];
var arr3 = [];
arr2.map(item => {
? if (arr3.indexOf(item) == -1) {
? ? arr3.push(item);
? }
});
console.log(arr3);
五骚露、深拷貝和淺拷貝
淺拷貝方法
1、展開運算符 ...
2缚窿、Object.assign({},對象)
深拷貝方法
1棘幸、JSON.parse(JSON.stringify(對象))
該方法有局限性
會忽略undefined
會忽略symbol
不能序列化函數(shù)
不能解決循環(huán)引用的對象
2、遞歸
function deepClone(obj) {
? //判斷是否為引用類型
? function isobj(o) {
? ? return (typeof o == "object" || typeof o == "function") && o !== null;
? }
? if (!isobj(obj)) {
? ? throw new Error("非對象");
? }
? //判斷是否為數(shù)組倦零,是的話解構(gòu)數(shù)組否則結(jié)構(gòu)對象
? let isArray = Array.isArray(obj);
? let newobj = isArray ? [...obj] : { ...obj };
? Object.keys(newobj).forEach(item => {
? ? newobj[item] = isobj(newobj[item]) ? deepClone(newobj[item]) : newobj[item];
? });
? return newobj;
}
六误续、繼承
1、原型繼承(通過prototype)
function Parent(name, age) {
? this.name = "小頭爸爸";
? this.age = 40;
}
function Child() {}
Child.prototype = new Parent();
var child = new Child();
console.log(child.name);
2光绕、構(gòu)造函數(shù)繼承()
function Parent(name) {
? this.name = name;
? this.age = 40;
}
function Child(name) {
? Parent.call(this, name);
}
var child = new Child("大頭兒子");
console.log(child.name);
console.log(child.age);
3女嘲、組合繼承
function Box(age) {
this.name = ['Lee', 'Jack', 'Hello']
this.age = age;
}
Box.prototype.run = function () {
return this.name + this.age;
};
function Desk(age) {
Box.call(this, age); //對象冒充
}
Desk.prototype = new Box(); //原型鏈繼承
var desk = new Desk(100);
alert(desk.run());
4、class繼承
class Parent {
? constructor(value) {
? ? this.value = value;
? }
? getvalue() {
? ? console.log(this.value);
? }
}
class Child extends Parent {
? constructor(value) {
? ? super(value);
? ? this.value = value;
? }
}
let child = new Child(1);
child.getvalue();
組合繼承優(yōu)點是可以用構(gòu)造函數(shù)傳參诞帐,可以復(fù)用父類的函數(shù)欣尼,不會與父類引用屬性共享,
缺點是子類原型上多了不需要的父類屬性
七停蕉、手寫call愕鼓、apply、bind
//手寫call慧起、apply菇晃、bind
//?Function.prototype.mycall?=?function(context)?{
//???if?(typeof?this?!==?"function")?{
//?????throw?new?TypeError("Error");
//???}
//???context?=?context?||?window;
//???context.fn?=?this;
//???let?args?=?[...arguments].slice(1);
//???let?result?=?context.fn(...args);
//???delete?context.fn;
//???return?result;
//?};
//?function?demo(num1,?num2)?{
//???let?rs?=?num1?+?num2;
//???console.log(rs);
//???return?rs;
//?}
//?demo.mycall(this,?1,?2);
//手寫apply
//?Function.prototype.myapply?=?function(context)?{
//???if?(typeof?this?!==?"function")?{
//?????throw?new?Error("Error");
//???}
//???context?=?context?||?window;
//???context.fn?=?this;
//???let?result;
//???if?(arguments[1])?{
//?????result?=?context.fn(...arguments[1]);
//???}?else?{
//?????result?=?context.fn();
//???}
//???delete?context.fn;
//???return?result;
//?};
//?function?demo(num1,?num2)?{
//???let?rs?=?num1?+?num2;
//???console.log(rs);
//???return?rs;
//?}
//?demo.myapply(this,?[1,?2]);
//手寫bind
Function.prototype.mybind?=?function(context)?{
??if?(typeof?this?!==?"function")?{
????throw?new?Error("Error");
??}
??console.log(arguments?instanceof?Object);
??let?args?=?[...arguments].slice(1);
??let?self?=?this;
??return?function?F()?{
????if?(this?instanceof?F)?{
??????return?new?self(...args,?...arguments);
????}?else?{
??????return?self.apply(context,?args.concat(...arguments));
????}
??};
};
function?demo(num1,?num2)?{
??let?rs?=?num1?+?num2;
??console.log(rs);
??return?rs;
}
demo.mybind(this,?1)(3,?6);
八、一個按鈕掛載兩個onclick事件
1蚓挤、寫兩個.addEventListener(click,fn1 )
addEventListener(click,fn2)
2磺送、寫onclick=“fn1()驻子;n2()”
知識點1
一、http緩存
二估灿、git常用命令
三崇呵、axios? 攔截器作用 底層原理
axios是什么
axios是基于promise機制實現(xiàn)的異步鏈?zhǔn)秸埱罂蚣埽w積小馅袁。
底層原理:promise+ajax
基本api
axios.get()get請求 獲取數(shù)據(jù)
axios.post()post請求 提交數(shù)據(jù)
axios.put()put請求 更新數(shù)據(jù)
axios.delete() 刪除數(shù)據(jù)
用法
對象使用:axios.get('url',params).then(response=>{
console.log(response)
})
函數(shù)使用:axios({
url:"url",
method:"method",
headers:?{'X-Requested-With':?'XMLHttpRequest'},
}).then((res)=>{console.log(err)}).catch((err)=>{console.log(err)})
axios.defaults.baseURL?=?'https://api.example.com';(設(shè)置基礎(chǔ)路徑)
axios.interceptors.request.use()請求攔截器
axios.interceptors.response.use()響應(yīng)攔截器
用法:
axios.interceptors.request.use((config)=>{
return config
},(error)=>{
return promise.reject(error)
})//兩種攔截器用法一樣域慷。
token怎么從后端獲取
四、優(yōu)化
1汗销、圖片優(yōu)化
⑴很多裝飾類的用css去完成犹褒。
⑵雪碧圖
⑶小圖使用base64格式
⑷選擇正確的格式
能使用webp就使用webp(webp兼容性不好,很多瀏覽器不支持)
小圖使用PNG弛针,大部分圖標(biāo)可以用SVG代替
照片使用JPEG
2叠骑、DNS預(yù)解析
DNS解析也是需要時間的,可以通過預(yù)解析的方式來預(yù)先獲得域名
<link rel="dns-prefetch" href="http://域名">
3削茁、節(jié)流
如果滾動事件會發(fā)起網(wǎng)絡(luò)請求座云,我們不希望用戶在滾動中一直發(fā)送網(wǎng)絡(luò)請求,而是而一段時間發(fā)送一次付材,對于這種情況我們可以使用節(jié)流
實現(xiàn)的主要思路:就是將當(dāng)前時間和上一次執(zhí)行時間作對比,如果差值大于設(shè)置的等待時間就執(zhí)行函數(shù)圃阳。
4厌衔、防抖
點擊按鈕會觸發(fā)網(wǎng)絡(luò)請求,我們不希望每次點擊都會觸發(fā)網(wǎng)絡(luò)請求捍岳,而是用戶點擊按鈕一段時間后沒有再次點擊的情況才去發(fā)起網(wǎng)絡(luò)請求富寿,對于這種情況我們可以使用防抖。
// func是用戶傳入需要防抖的函數(shù)// wait是等待時間const debounce = (func, wait = 50) => {
? // 緩存一個定時器id? let timer = 0? // 這里返回的函數(shù)是每次用戶實際調(diào)用的防抖函數(shù)? // 如果已經(jīng)設(shè)定過定時器了就清空上一次的定時器? // 開始一個新的定時器锣夹,延遲執(zhí)行用戶傳入的方法? return function(...args) {
? ? if (timer) clearTimeout(timer)
? ? timer = setTimeout(() => {
? ? ? func.apply(this, args)
? ? }, wait)
? }
}
5页徐、預(yù)加載
有些資源不需要馬上用到,但是需要盡早獲取银萍,這時候可以用到預(yù)加載
預(yù)加載其實是聲明式的fetch变勇,強制瀏覽器請求資源,并且不會阻塞onload事件贴唇,可以使用以下代碼實現(xiàn)預(yù)加載
<link rel="preload" href="資源">
優(yōu)點:降低首屏加載時間搀绣,缺點是兼容性不好
6、預(yù)渲染
可以通過預(yù)渲染將下載的文件在后臺渲染
實現(xiàn):<link rel="prerender" href="資源">
預(yù)渲染雖然可以提高頁面的加載速度戳气,但是要確保該頁面大概率會被用戶在之后打開链患,否則就是白白浪費資源去渲染。
7瓶您、懶執(zhí)行
將某些邏輯使用時在計算麻捻。該技術(shù)可以用于首屏優(yōu)化纲仍,一般可以通過定時器或者事件調(diào)用來喚醒
8、懶加載
將不關(guān)鍵的資源延后加載
原理是只加載可視區(qū)域
五贸毕、當(dāng)瀏覽器輸入url之后
https://www.cnblogs.com/confach/p/10050013.html
DNS查詢
TCP連接
發(fā)送HTTP請求
Server處理HTTP請求并返回HTTP報文
瀏覽器解析并render頁面
HTTP連接斷開
六郑叠、forEach和map的區(qū)別
1、返回值不一樣崖咨,forEach返回值是undefined锻拘,map返回值是一個新的數(shù)組
2、forEach不可中斷击蹲,除非拋出異常署拟。
七、this指向問題
1歌豺、定時器的this指向問題
setTimeout(function(){
console.log(this.name)
},1000)
一般情況下如果在定時器內(nèi)部使用普通函數(shù)推穷,this指向window
改變this指向的方法
⑴that綁定this
⑵使用bind,bind方法返回一個新函數(shù)类咧,call和apply立即執(zhí)行函數(shù)馒铃,所以只能使用bind方法,否則就失去了定時器的作用
⑶使用箭頭函數(shù)痕惋,箭頭函數(shù)沒有this指向区宇,它的this是繼承外部的作用域。
2值戳、如果直接調(diào)用函數(shù)议谷,函數(shù)不管放在哪個地方,this指向都是window
3堕虹、如果對象調(diào)用函數(shù)卧晓,this指向被調(diào)用的對象
4、對于new的方式赴捞,this永遠(yuǎn)綁定在實例化對象上逼裆,不可改變。
5赦政、箭頭函數(shù)沒有this指向胜宇,它的this是繼承外部的作用域。
八昼钻、webpack相關(guān)內(nèi)容
webpack相關(guān)內(nèi)容https://www.runoob.com/w3cnote/es6-setup.html
webpack功能:
1將sass/less 等預(yù)編譯的css語言轉(zhuǎn)換成瀏覽器識別的css文件
2能夠?qū)⒍鄠€預(yù)編譯文件打包成一個文件
3 打包image/styles/assets/scrips/等前端常用的文件
4 搭建開發(fā)環(huán)境開啟服務(wù)器
5 監(jiān)視文件改動掸屡,熱部署。
webpack構(gòu)建過程
從entry里配置的module開始遞歸解析entry依賴的所有module
每找到一個module然评,就會根據(jù)配置的loader去找對應(yīng)的轉(zhuǎn)換規(guī)則
對module進行轉(zhuǎn)換后仅财,再解析出當(dāng)前module依賴的module
這些模塊會以entry為單位分組,一個entry和其所有依賴的module被分到一個組Chunk
最后webpack會把所有Chunk轉(zhuǎn)換成文件輸出
在整個流程中webpack會在恰當(dāng)?shù)臅r機執(zhí)行plugin里定義的邏輯
webpack打包原理
將所有依賴打包成一個bundle.js碗淌,通過代碼分割成單元片段按需加載
什么是entry,output?
entry 入口盏求,告訴webpack要使用哪個模塊作為構(gòu)建項目的起點抖锥,默認(rèn)為./src/index.js
output 出口,告訴webpack在哪里輸出它打包好的代碼以及如何命名碎罚,默認(rèn)為./dist
什么是loader磅废,plugins?
loader是用來告訴webpack如何轉(zhuǎn)換某一類型的文件,并且引入到打包出的文件中荆烈。
plugins(插件)作用更大拯勉,可以打包優(yōu)化,資源管理和注入環(huán)境變量
什么是bundle,chunk,module?
bundle是webpack打包出來的文件憔购,chunk是webpack在進行模塊的依賴分析的時候宫峦,代碼分割出來的代碼塊。module是開發(fā)中的單個模塊
如何利用webpack來優(yōu)化前端性能
1. 壓縮代碼玫鸟。uglifyJsPlugin 壓縮js代碼导绷, mini-css-extract-plugin 壓縮css代碼
2. 利用CDN加速,將引用的靜態(tài)資源修改為CDN上對應(yīng)的路徑屎飘,可以利用webpack對于output參數(shù)和loader的publicpath參數(shù)來修改資源路徑
3. 刪除死代碼(tree shaking)妥曲,css需要使用Purify-CSS
4. 提取公共代碼。webpack4移除了CommonsChunkPlugin (提取公共代碼)钦购,用optimization.splitChunks和optimization.runtimeChunk來代替
補充CDN
CDN(Content Delivery Network)是指內(nèi)容分發(fā)網(wǎng)絡(luò)檐盟,也稱為內(nèi)容傳送網(wǎng)絡(luò),在現(xiàn)有互聯(lián)網(wǎng)基礎(chǔ)上建立一個內(nèi)容分發(fā)平臺專門為網(wǎng)站提供服務(wù)押桃,是為加快網(wǎng)絡(luò)訪問速度而被優(yōu)化的網(wǎng)絡(luò)覆蓋層遵堵,
原理
CDN的基本原理是廣泛采用各種緩存服務(wù)器,將這些緩存服務(wù)器分布到用戶訪問相對集中的地區(qū)或網(wǎng)絡(luò)中怨规,在用戶訪問網(wǎng)站時,利用全局負(fù)載技術(shù)將用戶的訪問指向距離最近的工作正常的緩存服務(wù)器上锡足,由緩存服務(wù)器直接響應(yīng)用戶請求
知識點2
一波丰、websocket介紹:https://www.liaoxuefeng.com/wiki/1022910821149312/1103303693824096
websocket簡單介紹
http://www.reibang.com/p/970dcfd174dc
二、koa
Koa 是一個新的 web 框架舶得,由 Express 幕后的原班人馬打造掰烟, 致力于成為 web 應(yīng)用和 API 開發(fā)領(lǐng)域中的一個更小、更富有表現(xiàn)力沐批、更健壯的基石纫骑。 通過利用 async 函數(shù),Koa 幫你丟棄回調(diào)函數(shù)九孩,并有力地增強錯誤處理先馆。 Koa 并沒有捆綁任何中間件, 而是提供了一套優(yōu)雅的方法躺彬,幫助您快速而愉快地編寫服務(wù)端應(yīng)用程序煤墙。
三梅惯、express
基于nodejs的web開發(fā)框架
四、nginx
Nginx?(engine x) 是一個高性能的HTTP和反向代理web服務(wù)器仿野,特點是占有內(nèi)存少铣减,并發(fā)能力強,事實上nginx的并發(fā)能力在同類型的網(wǎng)頁服務(wù)器中表現(xiàn)較好脚作,中國大陸使用nginx網(wǎng)站用戶有:百度葫哗、京東、新浪球涛、網(wǎng)易劣针、騰訊、淘寶等宾符。
功能:
Nginx是一個HTTP服務(wù)器酿秸,可以將服務(wù)器上的靜態(tài)文件(如HTML、圖片)通過HTTP協(xié)議展現(xiàn)給客戶端
可以實現(xiàn)負(fù)載均衡魏烫、虛擬主機
什么是負(fù)載均衡
當(dāng)網(wǎng)站訪問量非常大辣苏,網(wǎng)站站長開心賺錢的同時,也攤上事兒了哄褒。因為網(wǎng)站越來越慢稀蟋,一臺服務(wù)器已經(jīng)不夠用了。于是將同一個應(yīng)用部署在多臺服務(wù)器上呐赡,將大量用戶的請求分配給多臺機器處理退客。同時帶來的好處是,其中一臺服務(wù)器萬一掛了链嘀,只要還有其他服務(wù)器正常運行萌狂,就不會影響用戶使用。
Nginx可以通過反向代理來實現(xiàn)負(fù)載均衡怀泊。
虛擬主機
有的網(wǎng)站訪問量大茫藏,需要負(fù)載均衡。然而并不是所有網(wǎng)站都如此出色霹琼,有的網(wǎng)站务傲,由于訪問量太小,需要節(jié)省成本枣申,將多個網(wǎng)站部署在同一臺服務(wù)器上售葡。
例如將www.aaa.com和www.bbb.com兩個網(wǎng)站部署在同一臺服務(wù)器上,兩個域名解析到同一個IP地址忠藤,但是用戶通過兩個域名卻可以打開兩個完全不同的網(wǎng)站挟伙,互相不影響,就像訪問兩個服務(wù)器一樣模孩,所以叫兩個虛擬主機像寒。
五烘豹、nodejs
Node.js 是一個基于 Chrome V8 引擎的?JavaScript?運行環(huán)境。 Node.js 使用了一個事件驅(qū)動诺祸、非阻塞式 I/O 的模型携悯。?[1]?
Node 是一個讓 JavaScript 運行在服務(wù)端的開發(fā)平臺,它讓 JavaScript 成為與PHP筷笨、Python憔鬼、Perl、Ruby?等服務(wù)端語言平起平坐的腳本語言胃夏。
特點:
單線程
Node可以在不新增額外線程的情況下轴或,依然可以對任務(wù)進行并發(fā)處理 —— Node.js是單線程的。它通過事件循環(huán)(event loop)來實現(xiàn)并發(fā)操作仰禀,對此照雁,我們應(yīng)該要充分利用這一點 —— 盡可能的避免阻塞操作,取而代之答恶,多使用非阻塞操作饺蚊。
非阻塞IO
V8虛擬機
事件驅(qū)動
六、事件驅(qū)動
所謂事件驅(qū)動悬嗓,簡單地說就是你點什么按鈕(即產(chǎn)生什么事件)污呼,電腦執(zhí)行什么操作(即調(diào)用什么函數(shù)).當(dāng)然事件不僅限于用戶的操作. 事件驅(qū)動的核心自然是事件。從事件角度說包竹,事件驅(qū)動程序的基本結(jié)構(gòu)是由一個事件收集器燕酷、一個事件發(fā)送器和一個事件處理器組成。事件收集器專門負(fù)責(zé)收集所有事件周瞎,包括來自用戶的(如鼠標(biāo)苗缩、鍵盤事件等)、來自硬件的(如時鐘事件等)和來自軟件的(如操作系統(tǒng)声诸、應(yīng)用程序本身等)挤渐。事件發(fā)送器負(fù)責(zé)將收集器收集到的事件分發(fā)到目標(biāo)對象中。事件處理器做具體的事件響應(yīng)工作双絮,它往往要到實現(xiàn)階段才完全確定,因而需要運用虛函數(shù)機制(函數(shù)名往往取為類似于HandleMsg的一個名字)得问。對于框架的使用者來說囤攀,他們唯一能夠看到的是事件處理器。這也是他們所關(guān)心的內(nèi)容
七宫纬、非阻塞i/o
非阻塞I/O是指以異步來執(zhí)行函數(shù)焚挠,先執(zhí)行同步任務(wù),耗時任務(wù)放在事件隊列中漓骚,以此輪詢執(zhí)行蝌衔。
八榛泛、webpack和gulp
二者比較
gulp它是基于流的自動化構(gòu)建工具。有task處理機制噩斟,入口是src曹锨,通過管道pipe打包文件。配置文件是gulpfile.js
webpack的兩大特點:1模塊化 2打包剃允。Webpack實現(xiàn)了模塊化開發(fā)和文件處理沛简。它能夠?qū)⒏鱾€模塊進行按需加載,不會導(dǎo)致加載了無用或冗余的代碼斥废。配置文件webpack.config.js
功能:
1將sass/less 等預(yù)編譯的css語言轉(zhuǎn)換成瀏覽器識別的css文件
2能夠?qū)⒍鄠€預(yù)編譯文件打包成一個文件
3 打包image/styles/assets/scrips/等前端常用的文件
4 搭建開發(fā)環(huán)境開啟服務(wù)器
5 監(jiān)視文件改動椒楣,熱部署。
九牡肉、模塊化
模塊化的優(yōu)點
解決命名沖突
提供復(fù)用性
提高代碼可維護性
實現(xiàn):
CommonJs
隨著Javasript應(yīng)用進軍服務(wù)器端捧灰,業(yè)界急需一種標(biāo)準(zhǔn)的模塊化解決方案,于是统锤,CommonJS(www.commonjs.org)應(yīng)運而生毛俏。它最初是由Kevin Dangoor在他的這篇博文中首次提出。
這是一種被廣泛使用的Javascript模塊化規(guī)范跪另,大家最熟悉的Node.js應(yīng)用中就是采用這個規(guī)范拧抖。在Node.js中,內(nèi)置了module對象用來定義模塊, require函數(shù)用來加載模塊文件免绿,代碼如下:
// utils.js 模塊定義var add = function(a, b) {
? ? return a + b;
};
module.exports = {
? ? add: add
};// 加載模塊var utils = require('./utils');console.log(utils.add(1, 2));
此種模塊化方案特點就是:同步阻塞式加載唧席,無法實現(xiàn)按需異步加載。另外嘲驾,如果想要在瀏覽器中使用CommonJS模塊就需要使用Browserify進行解析:
npm install browserify -g
browserify utils.js > bundle.js
當(dāng)然淌哟,你也可以使用gulp, webpack等工具進行解析打包后引入到瀏覽器頁面中去。
ES6 Modules
對于ES6來說辽故,不必再使用閉包和封裝函數(shù)等方式進行模塊化支持了徒仓。在ES6中,從語法層面就提供了模塊化的功能誊垢。然而受限于瀏覽器的實現(xiàn)程度掉弛,如果想要在瀏覽器中運行,還是需要通過Babel等轉(zhuǎn)譯工具進行編譯喂走。ES6提供了import和export命令殃饿,分別對應(yīng)模塊的導(dǎo)入和導(dǎo)出功能。具體實例如下:
// demo-export.js 模塊定義var name = "scq000"var sayHello = (name) => {
? console.log("Hi芋肠," + name);
}export {name, sayHello};// demo-import.js 使用模塊import {sayHello} from "./demo-export";
sayHello("scq000");
對于具體的語法細(xì)節(jié)乎芳,想必大家在日常使用過程中都已經(jīng)輕車熟路了。但對于ES6模塊化來說,有以下幾點特性是需要記住的:
ES6使用的是基于文件的模塊奈惑。所以必須一個文件一個模塊吭净,不能將多個模塊合并到單個文件中去。
ES6模塊API是靜態(tài)的肴甸,一旦導(dǎo)入模塊后寂殉,無法再在程序運行過程中增添方法。
ES6模塊采用引用綁定(可以理解為指針)雷滋。這點和CommonJS中的值綁定不同不撑,如果你的模塊在運行過程中修改了導(dǎo)出的變量值,就會反映到使用模塊的代碼中去晤斩。所以焕檬,不推薦在模塊中修改導(dǎo)出值,導(dǎo)出的變量應(yīng)該是靜態(tài)的澳泵。
ES6模塊采用的是單例模式实愚,每次對同一個模塊的導(dǎo)入其實都指向同一個實例
Webpack中的模塊化方案
作為現(xiàn)代化的前端構(gòu)建工具,Webpack還提供了豐富的功能能夠使我們更加輕易地實現(xiàn)模塊化兔辅。利用Webpack腊敲,你不僅可以將Javascript文件進行模塊化,同時還能針對圖片维苔,css等靜態(tài)資源進行模塊化碰辅。你可以在代碼里使用CommonJS, ES6等模塊化語法,打包的時候你也可以根據(jù)需求選擇打包類型介时,如UMD, AMD等:
module.exports = {
? //...
? output: {
? ? library: 'librayName',
? ? libraryTarget: 'umd', // 配置輸出格式
? ? filename: 'bundle.js'
? }
};
另外没宾,ES6模塊好處很多,但是并不支持按需加載的功能, 而按需加載又是Web性能優(yōu)化中重要的一個環(huán)節(jié)沸柔。好在我們可以借助Webpack來彌補這一缺陷循衰。Webpack v1版本提供了require.ensureAPI, 而2.x之后使用了import()函數(shù)來實現(xiàn)異步加載。具體的代碼示例可以查看我之前所寫的前端性能優(yōu)化之加載技術(shù)?這篇文章褐澎。
十会钝、mvvm mvc
PS:MVVM(Model-View-ViewModel), 源自于經(jīng)典的 Model–View–Controller(MVC)模式。MVVM 的出現(xiàn)促進了 GUI 前端開發(fā)與后端業(yè)務(wù)邏輯的分離工三,極大地提高了前端開發(fā)效率迁酸。MVVM 的核心是 ViewModel 層,它就像是一個中轉(zhuǎn)站(value converter)俭正,負(fù)責(zé)轉(zhuǎn)換 Model 中的數(shù)據(jù)對象來讓數(shù)據(jù)變得更容易管理和使用奸鬓,該層向上與視圖層進行雙向數(shù)據(jù)綁定,向下與 Model 層通過接口請求進行數(shù)據(jù)交互段审,起呈上啟下作用。View 層展現(xiàn)的不是 Model 層的數(shù)據(jù),而是 ViewModel 的數(shù)據(jù)寺枉,由 ViewModel 負(fù)責(zé)與 Model 層交互抑淫,這就完全解耦了 View 層和 Model 層,這個解耦是至關(guān)重要的姥闪,它是前后端分離方案實施的最重要一環(huán)始苇。
十一、ajax 筐喳、axios、fetch
Ajax
傳統(tǒng) Ajax 指的是 XMLHttpRequest(XHR), 最早出現(xiàn)的發(fā)送后端請求技術(shù)反璃,隸屬于原始js中笨奠,核心使用XMLHttpRequest對象,多個請求之間如果有先后關(guān)系的話梳毙,就會出現(xiàn)回調(diào)地獄哺窄。
JQuery ajax 是對原生XHR的封裝,除此以外還增添了對JSONP的支持账锹。經(jīng)過多年的更新維護萌业,真的已經(jīng)是非常的方便了,奸柬;如果是硬要舉出幾個缺點生年,那可能只有:
1.本身是針對MVC的編程,不符合現(xiàn)在前端MVVM的浪潮
2.基于原生的XHR開發(fā),XHR本身的架構(gòu)不清晰廓奕。
3.JQuery整個項目太大抱婉,單純使用ajax卻要引入整個JQuery非常的不合理(采取個性化打包的方案又不能享受CDN服務(wù))
4.不符合關(guān)注分離(Separation of Concerns)的原則
5.配置和調(diào)用方式非常混亂懂从,而且基于事件的異步模型不友好授段。
PS:MVVM(Model-View-ViewModel), 源自于經(jīng)典的 Model–View–Controller(MVC)模式。MVVM 的出現(xiàn)促進了 GUI 前端開發(fā)與后端業(yè)務(wù)邏輯的分離番甩,極大地提高了前端開發(fā)效率侵贵。MVVM 的核心是 ViewModel 層,它就像是一個中轉(zhuǎn)站(value converter)缘薛,負(fù)責(zé)轉(zhuǎn)換 Model 中的數(shù)據(jù)對象來讓數(shù)據(jù)變得更容易管理和使用窍育,該層向上與視圖層進行雙向數(shù)據(jù)綁定,向下與 Model 層通過接口請求進行數(shù)據(jù)交互宴胧,起呈上啟下作用漱抓。View 層展現(xiàn)的不是 Model 層的數(shù)據(jù),而是 ViewModel 的數(shù)據(jù)恕齐,由 ViewModel 負(fù)責(zé)與 Model 層交互乞娄,這就完全解耦了 View 層和 Model 層,這個解耦是至關(guān)重要的,它是前后端分離方案實施的最重要一環(huán)仪或。
axios
axios 是一個基于Promise 用于瀏覽器和 nodejs 的 HTTP 客戶端确镊,本質(zhì)上也是對原生XHR的封裝,只不過它是Promise的實現(xiàn)版本范删,符合最新的ES規(guī)范蕾域,它本身具有以下特征:
注:
1、從瀏覽器創(chuàng)建XMLHttpRequest
2到旦、node.js發(fā)送http請求
3旨巷、支持promiseAPI
4、攔截請求和響應(yīng)
5添忘、轉(zhuǎn)換請求和響應(yīng)
6采呐、取消請求
7、JSON數(shù)據(jù)的自動轉(zhuǎn)換
8昔汉、客戶端對防止XSRF的支持
PS:防止CSRF:就是讓你的每個請求都帶一個從cookie中拿到的key, 根據(jù)瀏覽器同源策略懈万,假冒的網(wǎng)站是拿不到你cookie中得key的,這樣靶病,后臺就可以輕松辨別出這個請求是否是用戶在假冒網(wǎng)站上的誤導(dǎo)輸入会通,從而采取正確的策略。
axios既提供了并發(fā)的封裝,而且體積也較小娄周,當(dāng)之無愧現(xiàn)在最應(yīng)該選用的請求的方式涕侈。
fetch
fetch號稱是AJAX的替代品,是在ES6出現(xiàn)的煤辨,使用了ES6中的promise對象裳涛。Fetch是基于promise設(shè)計的。Fetch的代碼結(jié)構(gòu)比起ajax簡單多了众辨,參數(shù)有點像jQuery ajax端三。但是,一定記住fetch不是ajax的進一步封裝鹃彻,而是原生js郊闯,沒有使用XMLHttpRequest對象。
fetch的優(yōu)點:
1.符合關(guān)注分離蛛株,沒有將輸入团赁、輸出和用事件來跟蹤的狀態(tài)混雜在一個對象里
2.更好更方便的寫法
坦白說,上面的理由對我來說完全沒有什么說服力谨履,因為不管是Jquery還是Axios都已經(jīng)幫我們把xhr封裝的足夠好欢摄,使用起來也足夠方便,為什么我們還要花費大力氣去學(xué)習(xí)fetch笋粟?
我認(rèn)為fetch的優(yōu)勢主要優(yōu)勢就是:
1.? 語法簡潔怀挠,更加語義化
2.? 基于標(biāo)準(zhǔn) Promise 實現(xiàn)析蝴,支持 async/await
3.? 同構(gòu)方便,使用 [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)
4.更加底層绿淋,提供的API豐富(request, response)
5.脫離了XHR嫌变,是ES規(guī)范里新的實現(xiàn)方式
十二、有關(guān)于異步的問題
promise
是異步編程的一種解決方案躬它。
從語法上說,Promise 是一個對象东涡,從它可以獲取異步操作的消息冯吓。
Promise 狀態(tài)以及狀態(tài)的特點
Promise 異步操作有三種狀態(tài):pending(進行中)、fulfilled(已成功)和 rejected(已失敶堋)组贺。除了異步操作的結(jié)果,任何其他操作都無法改變這個狀態(tài)祖娘。
Promise 對象只有:從 pending 變?yōu)?fulfilled 和從 pending 變?yōu)?rejected 的狀態(tài)改變失尖。只要處于 fulfilled 和 rejected ,狀態(tài)就不會再變了即 resolved(已定型)渐苏。
狀態(tài)的缺點
無法取消 Promise 掀潮,一旦新建它就會立即執(zhí)行,無法中途取消琼富。
如果不設(shè)置回調(diào)函數(shù)仪吧,Promise 內(nèi)部拋出的錯誤,不會反應(yīng)到外部鞠眉。
當(dāng)處于 pending 狀態(tài)時薯鼠,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。械蹋、
then 方法接收兩個函數(shù)作為參數(shù)出皇,第一個參數(shù)是 Promise 執(zhí)行成功時的回調(diào),第二個參數(shù)是 Promise 執(zhí)行失敗時的回調(diào)哗戈,兩個函數(shù)只會有一個被調(diào)用郊艘。
generator
yield是ES6的新關(guān)鍵字,使生成器函數(shù)執(zhí)行暫停谱醇,yield關(guān)鍵字后面的表達式的值返回給生成器的調(diào)用者暇仲。它可以被認(rèn)為是一個基于生成器的版本的return關(guān)鍵字。
yield關(guān)鍵字實際返回一個IteratorResult(迭代器)對象副渴,它有兩個屬性奈附,value和done,分別代表返回值和是否完成煮剧。
yield無法單獨工作斥滤,需要配合generator(生成器)的其他函數(shù)将鸵,如next,懶漢式操作佑颇,展現(xiàn)強大的主動控制特性顶掉。
function *gen() {
? ? yield 'hello';
? ? yield 'world';
? ? return true;
}
以上代碼定義了一個簡單的 generator,看起來就像一個普通的函數(shù)挑胸,區(qū)別是function關(guān)鍵字后面有個*號痒筒,函數(shù)體內(nèi)可以使用yield語句進行流程控制。
?var iter?=?gen();
?var a?= iter.next();
?console.log(a);?// {value:'hello', done:false}
?var b?= iter.next();
?console.log(b);?// {value:'world', done:false}
?var c?= iter.next();
?console.log(c);?// {value:true, done:true}
當(dāng)執(zhí)行g(shù)en()的時候茬贵,并不執(zhí)行 generator 函數(shù)體簿透,而是返回一個迭代器。迭代器具有next()方法解藻,每次調(diào)用 next() 方法老充,函數(shù)就執(zhí)行到y(tǒng)ield語句的地方。next() 方法返回一個對象螟左,其中value屬性表示 yield 關(guān)鍵詞后面表達式的值啡浊,done 屬性表示是否遍歷結(jié)束。generator 生成器通過next和yield的配合實現(xiàn)流程控制胶背,上面的代碼執(zhí)行了三次 next() 巷嚣,generator 函數(shù)體才執(zhí)行完畢。
async
async 函數(shù)返回一個 Promise 對象
function testAwait(){? return new Promise((resolve) => {? ? ? setTimeout(function(){? ? ? ? ? console.log("testAwait");
? ? ? ? ? resolve();
? ? ? }, 1000);
? });} async function helloAsync(){? await testAwait();
? console.log("helloAsync");
}helloAsync();// testAwait// helloAsync
await針對所跟不同表達式的處理方式:
Promise 對象:await 會暫停執(zhí)行钳吟,等待?Promise 對象 resolve涂籽,然后恢復(fù) async 函數(shù)的執(zhí)行并返回解析值。
非 Promise 對象:直接返回對應(yīng)的值砸抛。
十三评雌、Object.keys()和Reflect.ownKeys()區(qū)別
Object.keys()返回屬性key,但不包括不可枚舉的屬性
Reflect.ownKeys()返回所有屬性key
他們兩個都不能遍歷原型上的屬性
擴展
for in
for in一般用于遍歷對象的屬性直焙;
作用于數(shù)組的for in除了會遍歷數(shù)組元素外景东,還會遍歷自定義可枚舉的屬性,以及原型鏈上可枚舉的屬性奔誓;
作用于數(shù)組的for in的遍歷結(jié)果是數(shù)組的索引斤吐,且都為字符串型,不能用于運算厨喂;
某些情況下和措,可能按照隨機順序遍歷數(shù)組元素;
for of
ES6中添加的循環(huán)語法蜕煌;
for of支持遍歷數(shù)組派阱、類對象(例如DOM NodeList對象)、字符串斜纪、Map對象贫母、Set對象文兑;
for of不支持遍歷普通對象,可通過與Object.keys()搭配使用遍歷腺劣;
for of遍歷后的輸出結(jié)果為數(shù)組元素的值绿贞;
十四、頁面卡頓的原因
1橘原、js運行時間太長
2籍铁、head加載js時一直沒加載出來
3、dom過多
4趾断、首屏加載資源過大(解決:默認(rèn)資源站位)
十五寨辩、瀏覽器存儲(cookie 、webstorage)
https://www.cnblogs.com/qiujianmei/p/10824682.html
React
一歼冰、子組件向父組件傳值
父子組件通信不僅可以傳值,還可以傳遞方法耻警,父組件將更新數(shù)據(jù)的方法拿給子組件使用隔嫡,子組件將自身的數(shù)據(jù)傳入這個方法并調(diào)用,以此來改變父組件的數(shù)據(jù)甘穿。
就是父組件給子組件傳遞一個方法腮恩,子組件將自己的數(shù)據(jù)傳入這個方法并調(diào)用,就能改變父組件數(shù)據(jù)
二温兼、父組件調(diào)用子組件的方法
先向子組件傳方法秸滴,子組件通過父組件傳遞的方法向父組件傳遞方法,父組件獲取到子組件的方法直接調(diào)用募判。
三荡含、state和prop的區(qū)別
2-1.prop用于定義外部接口,state用于記錄內(nèi)部狀態(tài)
2-2届垫,prop 的賦值在外部世界使用組件時释液,state的賦值在組件內(nèi)部,
2-3装处,組件不應(yīng)該改變prop的值误债,而state存在的目的就是讓組件來改變的
四、修改數(shù)據(jù)應(yīng)該在哪個生命周期里面
didMount妄迁、didUpdate()
五寝蹈、虛擬dom
1、瀏覽器資源對dom節(jié)點開銷很大登淘,而且頻繁改變dom結(jié)點箫老,會引發(fā)重繪和回流,非常影響性能黔州。
2槽惫、虛擬dom存在的意義就是為了減少對實際dom的操作周叮,js運行速度很快,通過對比新舊dom界斜,有針對性的把差異部分渲染到頁面上
3仿耽、虛擬dom原理:
⑴用js模擬dom樹,并渲染dom樹
⑵比較新老dom樹各薇,得到比較的差異對象
⑶把差異對象應(yīng)用到渲染的dom樹
4项贺、js創(chuàng)建虛擬dom
5、diff算法
作用:是用來計算出 Virtual DOM 中被改變的部分峭判,然后針對該部分進行原生DOM操作开缎。
createElement(tag,props林螃,children)
策略:策略一(tree diff):
Web UI中DOM節(jié)點跨層級的移動操作特別少奕删,可以忽略不計。
? 策略二(component diff):
擁有相同類的兩個組件 生成相似的樹形結(jié)構(gòu)疗认,
擁有不同類的兩個組件 生成不同的樹形結(jié)構(gòu)完残。
? 策略三(element diff):
對于同一層級的一組子節(jié)點,通過唯一id區(qū)分横漏。
六谨设、react生命周期
https://www.cnblogs.com/kdcg/p/9182393.html
1、construtor():構(gòu)造函數(shù)
組建加載前最先調(diào)用一次缎浇,僅調(diào)用一次
作用:定義狀態(tài)機變量
2扎拣、componentWillMount
組件初始渲染(render()被調(diào)用)前調(diào)用,僅調(diào)用一次素跺。
如果這個函數(shù)調(diào)用的setState改變了組件的某些狀態(tài)二蓝,react會等待setState完成后再渲染組件
注意子組件也有componentWillMount函數(shù),在父組件的該函數(shù)調(diào)用后在調(diào)用指厌。
3侣夷、render()
執(zhí)行:componentWillMount調(diào)用之后,componentDidMount調(diào)用之前
作用:渲染掛載組件仑乌。
觸發(fā):⑴初始化加載頁面百拓,⑵狀態(tài)機改變setState,⑶接受新的props(父組件更新)
注意:這是組件必要參數(shù)晰甚,不能在該函數(shù)內(nèi)使用setState改變狀態(tài)機
4衙传、componentDidMount()
執(zhí)行:render()之后被調(diào)用,僅調(diào)用一次厕九。
作用:渲染掛載組件
注意:子組件也有該函數(shù)蓖捶,在父組件調(diào)用前調(diào)用,如果該函數(shù)有setState改變狀態(tài)機扁远,將重新渲染組件俊鱼,如果需要在頁面初始化之后才改變狀態(tài)機的刻像,可以將網(wǎng)絡(luò)請求放在該函數(shù)內(nèi)。
5并闲、componentWillReceiveProps()
執(zhí)行:組件渲染后细睡,當(dāng)組件接收新的參數(shù)時被調(diào)用,
6帝火、shouldComponentUpDate(nextProps溜徙,nextState)
執(zhí)行:組件執(zhí)行render()函數(shù)之后,接收新的props或state時被調(diào)用犀填,即每次執(zhí)行setState都會執(zhí)行該函數(shù)蠢壹,來判斷是否重新渲染組件,默認(rèn)返回true九巡,接收兩個參數(shù)图贸。
作用:如果有些變化不需要執(zhí)行渲染組件,可在該函數(shù)內(nèi)阻止冕广,
注意:不能在該函數(shù)內(nèi)使用setState來改變狀態(tài)機疏日。
7、componentDidUpdate()
執(zhí)行:組件重新渲染后調(diào)用佳窑,初始化渲染的時候該方法不會被調(diào)用。
作用:使用該方法可以在組件更新后操作dom元素
8父能、componentWillUnmount()
執(zhí)行:組件卸載之前被調(diào)用
作用:在該方法中執(zhí)行必要的清理神凑,比如無效的定時器
注意:當(dāng)一個頁面中存在父子組件的時候,要特別注意componentDidMount的使用何吝,因為子組件componentDidMount會比父組件先調(diào)用溉委,從而引起父子組件傳參錯誤
七、Component與PureComponent的區(qū)別
https://www.cnblogs.com/ly0612/p/11954414.html
PureComponent簡單實現(xiàn)了shouldComponentUpdate()的功能爱榕。當(dāng)然數(shù)據(jù)結(jié)構(gòu)比較復(fù)雜就不行了瓣喊。
PureComponent缺點
可能會因深層的數(shù)據(jù)不一致而產(chǎn)生錯誤的否定判斷,從而shouldComponentUpdate結(jié)果返回false黔酥,界面得不到更新藻三。
八、怎么寫一個組件
https://blog.csdn.net/donspeng/article/details/83421136
組件目的是為了提高代碼復(fù)用性跪者,另外棵帽,組件必須功能單一,復(fù)用性高渣玲。如果想實現(xiàn)復(fù)用性強的特點的話逗概,可以用高階組件的思想,傳參數(shù)通過props
九忘衍、connect()參數(shù)有幾個
函數(shù)將被調(diào)用兩次逾苫。第一次是設(shè)置參數(shù)卿城,第二次是組件與 Redux store 連接:connect(mapStateToProps, mapDispatchToProps, mergeProps)(MyComponent)。
十铅搓、路由
十一瑟押、react優(yōu)化
十二、服務(wù)器渲染
十三狸吞、react hooks方法有哪些方法
1勉耀、基礎(chǔ) Hook
useState
useEffect
useContext
2、額外的 Hook
useReducer
useCallback
useMemo
useRef
useImperativeHandle
useLayoutEffect
useDebugValue
十四蹋偏、setState
什么時候setState是同步的
1便斥、React通過addEventListener直接添加事件處理函數(shù),
2威始、通過setTimeout/setInterval產(chǎn)生異步調(diào)用
原理解析:
在React的setState函數(shù)實現(xiàn)中枢纠,會根據(jù)一個變量 isBatchingUpdate 來判斷是直接同步更新this.state還是放到隊列中異步更新 。這個變量默認(rèn)為false即同步執(zhí)行黎棠,而當(dāng) React 在調(diào)用事件處理函數(shù)之前就會調(diào)用這個 batchedUpdates晋渺,這個函數(shù)會把isBatchingUpdate變?yōu)閠rue,然后異步執(zhí)行setState脓斩。
React使用了事務(wù)的機制木西,React的每個生命周期和合成事件都處在一個大的事務(wù)當(dāng)中。在事務(wù)的前置鉤子中調(diào)用batchedUpdates方法修改isBatchingUpdates變量為true随静,在后置鉤子中將變量置為false八千。原生綁定事件和setTimeout異步的函數(shù)沒有進入到React的事務(wù)當(dāng)中,或者當(dāng)他們執(zhí)行時燎猛,剛剛的事務(wù)已近結(jié)束了恋捆,后置鉤子觸發(fā)了,所以此時的setState會直接進入非批量更新模式重绷,表現(xiàn)在我們看來成為了同步SetState
十五沸停、淺談redux
最外層是Provider(react-redux解構(gòu)出來)<Provider store={store}>
然后是store, store里面是reducer
reducer傳兩個參數(shù)(state,action)返回新的state
頁面用connect(mapstate昭卓,dispatchstate愤钾,組件)或者使用裝飾器
為什么reducer是純函數(shù)
因為不能改變輸入值state,說白了就是reducer傳state和action返回新的state
為什么這樣設(shè)計
因為頁面渲染需要比較新舊state候醒,react比較state比較的是地址(也就是淺比較绰垂,如果深比較耗費性能)所以必須返回新的state,否則頁面不更新
首先得先知道什么是純函數(shù)
1火焰、相同的輸入永遠(yuǎn)返回相同的輸出
2劲装、不能修改輸入值
3、不依賴外部環(huán)境
4、無任何副作用
十六占业、React組件有那些
可分為函數(shù)組件绒怨,class組件、渲染組件谦疾、組合組件南蹂、有狀態(tài)組件、無狀態(tài)組件念恍、高階組件六剥、自定義組件