一、CSS相關(guān)問題
1骚露、 行內(nèi)元素,塊級(jí)元素,空元素
- 行內(nèi)元素有:
a b span select strong(強(qiáng)調(diào)的語氣)
- 塊級(jí)元素有:
div ul ol li dl dt dd h1 h2 h3 h4…p
- 行內(nèi)塊元素:
img, input, textarea
- 常見的空元素:
<br> <hr> <img> <input> <link> <meta>
鮮為人知的是:
<area> <base> <col> <command> <embed> <keygen> <param> <source> <track> <wbr>
2、選擇器優(yōu)先級(jí)
important(1,0,0,0) > 內(nèi)聯(lián) > id(0,1,0,0) > class(0,0,1,0) = 屬性 = 偽類( 0,0,1,0) >標(biāo)簽(0,0,0,1) = 偽元素(0,0,0,1) > 通配符(* 0,0,0,0)
3、水平垂直居中
- 定位 + transform
//父元素設(shè)置position: relative;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
- 行內(nèi)塊元素 + 標(biāo)尺
1.給它的父元素寫text-align屬性愕鼓;
2.要居中的元素將其類型轉(zhuǎn)為inline-block蚓挤;
3.要居中的元素加vertical-align屬性;
4.添加一個(gè)“標(biāo)尺”馅袁,既同級(jí)元素(span等)抵窒,要居中的元素與其互相垂直居中
注意在編輯時(shí)標(biāo)尺與需要居中的元素之間不能有空格回車;
標(biāo)尺須加:
display:inline-block朦拖;
//目的是隱藏標(biāo)尺
width:0富寿;
//與父元素等高,中線位置既是居中位置
height:100%;
vertical-align:middle;
<style>
*{
margin: 0;
padding: 0;
}
.div1{
width: 200px;
height: 150px;
background: blue;
margin: 20px 20px;
text-align: center;
}
.div1-1{
width: 100px;
height: 100px;
background: red;
display: inline-block;
vertical-align: middle;
}
.div1 span{
display: inline-block;
width: 0px;
height: 100%;
background: #0681D0;
vertical-align: middle;
}
</style>
<div class="div1">div1
<div class="div1-1">div2</div><span></span>
</div>
4链患、動(dòng)畫問題
5贸毕、寫個(gè)左右布局,左邊固定寬度,右邊自適應(yīng)
- 左浮動(dòng) + 右不設(shè)寬(使用float需要注意清除浮動(dòng)造成父元素塌陷的問題)
- 左定位 + 右不設(shè)寬
- flex布局
6、寫六點(diǎn)篩子布局
- flex布局
<style>
h2{
text-align: center;
}
.main{
display: flex;
flex-wrap: wrap;
width: 680px;
justify-content: space-between;
}
.container{
display: flex;
width: 320px;
height: 320px;
flex-wrap: wrap;
justify-content: space-between;
align-content:space-between;
}
.box{
width: 90px;
height: 90px;
background-color: #EEEEEE;
padding: 5px;
border-radius: 5px;
display: flex;
flex-wrap: wrap;
}
.row{
display: flex;
flex-basis: 100%;
}
.item{
width: 24px;
height: 24px;
background-color: #000000;
margin: 3px;
border-radius: 50%;
}
/*排列方向*/
.flex-direction-column{
flex-direction: column;
}
/*水平排列*/
.justify-content-center{
justify-content: center;
}
.justify-content-flex-end{
justify-content: flex-end;
}
.justify-content-space-between{
justify-content: space-between;
}
/*垂直排列*/
.align-items-center{
align-items: center;
}
.align-items-flex-end{
align-items: flex-end;
}
.align-items-space-between{
align-items: space-between;
}
/*多軸對(duì)齊*/
.align-content-space-between{
align-content: space-between;
}
/*項(xiàng)目排列*/
.align-self-center{
align-self: center;
}
.align-self-flex-end{
align-self: flex-end;
}
</style>
<div class="container">
<div class="box justify-content-center align-items-center">
<span class="item"></span>
</div>
<div class="box justify-content-space-between">
<span class="item"></span>
<span class="item align-self-flex-end"></span>
</div>
<div class="box">
<span class="item"></span>
<span class="item align-self-center"></span>
<span class="item align-self-flex-end"></span>
</div>
<div class="box align-content-space-between">
<div class="row justify-content-space-between">
<span class="item"></span>
<span class="item"></span>
</div>
<div class="row justify-content-space-between">
<span class="item"></span>
<span class="item"></span>
</div>
</div>
<div class="box">
<div class="row justify-content-space-between">
<span class="item"></span>
<span class="item"></span>
</div>
<div class="row justify-content-center">
<span class="item"></span>
</div>
<div class="row justify-content-space-between">
<span class="item"></span>
<span class="item"></span>
</div>
</div>
<div class="box align-content-space-between flex-direction-column">
<span class="item"></span>
<span class="item"></span>
<span class="item"></span>
<span class="item"></span>
<span class="item"></span>
<span class="item"></span>
</div>
</div>
二、JS
1议谷、js基本類型逼裆,如何判別類型
數(shù)據(jù)類型分為基本類型和引用類型:
基本類型:String恢着、Number、Boolean盏求、Null荆烈、Undefined玫鸟、symbol(ES6)
引用類型:Object、Array、Date、Function、Error掰烟、RegExp先馆、Math、Number宪拥、String仿野、Boolean、Globle她君。
js內(nèi)置類型有七種:String脚作、Number灭翔、Boolean、Null、Undefined售葡、Symbol(ES6)、Object
判斷數(shù)據(jù)類型的幾種方式優(yōu)缺點(diǎn)對(duì)比
不同類型的優(yōu)缺點(diǎn) | typeof | instanceof | constructor | object.prototype.toString.call() |
---|---|---|---|---|
優(yōu)點(diǎn) | 使用簡(jiǎn)單 | 能檢測(cè)出引用類型 | 基本能檢測(cè)出所有類型(null和Undefined除外) | 所有類型 |
缺點(diǎn) | 基本類型(null不行) | 基本類型不行昌跌,且不能跨iframe | constructor易修改包竹,且不能跨iframe | IE6以下null和Undefined為Object |
2、js數(shù)組的方法都看下
注意: 可參考https://www.cnblogs.com/sqh17/p/8529401.html
數(shù)組方法 | 作用 | 返回值 | 備注 |
---|---|---|---|
arr.push() | 從后面添加元素 | 添加完后的數(shù)組的長(zhǎng)度 | 無 |
arr.pop() | 從后面刪除元素 | 刪除的元素 | 只能刪除一個(gè) |
arr.shift() | 從前面刪除元素 | 刪除的元素 | 只能刪除一個(gè) |
arr.unshift() | 從前面添加元素 | 添加完后的數(shù)組的長(zhǎng)度 | 無 |
arr.splice(i,n) | 刪除從i(索引值)開始之后的那個(gè)元素 | 刪除的元素 | 無 |
arr.concat(i,n) | 連接兩個(gè)數(shù)組 | 連接后的新數(shù)組 | 無 |
arr.split() | 將字符串轉(zhuǎn)化為數(shù)組 | 數(shù)組 | 無 |
arr.sort() | 將數(shù)組進(jìn)行排序 | 排好的數(shù)組 | 默認(rèn)是按照最左邊的數(shù)字進(jìn)行排序(1,10,2) |
arr.reverse() | 將數(shù)組反轉(zhuǎn) | 反轉(zhuǎn)后的數(shù)組 | 無 |
arr.slice(start,end) | 切去索引值start到索引值end的數(shù)組孤个,不包含end索引的值 | 切出來的數(shù)組 | 無 |
arr.forEach(callback) | 遍歷數(shù)組,無return | 無 | 會(huì)影響原來的數(shù)組 |
arr.map(callback) | 映射數(shù)組(遍歷數(shù)組) | 返回一個(gè)新數(shù)組 | 數(shù)組長(zhǎng)度與原數(shù)組相同(不滿足同條件的為空) |
arr.filter(callback) | 過濾數(shù)組 | 返回一個(gè)新數(shù)組 | 實(shí)際滿足條件的數(shù)組 |
arr.every(callback) | 依據(jù)判斷條件煌寇,數(shù)組的元素是否全滿足 | ture/false | 全滿足返回true |
arr.some() | 依據(jù)判斷條件,數(shù)組的元素是否全滿足 | ture/false | 若有一個(gè)滿足則返回ture |
arr.find(callback) | 找到第一個(gè)符合條件的數(shù)組成員 | 無 | |
arr.reduce(callback, initialValue) | 迭代數(shù)組的所有項(xiàng)奈惑,累加器姆坚,數(shù)組中的每個(gè)值(從左到右)合并没宾,最終計(jì)算為一個(gè)值 | 返回一個(gè)值 | 無 |
arr.indexOf() | 查找某個(gè)元素的索引值 | 若有重復(fù)的奸鬓,則返回第一個(gè)查到的索引值若不存在梳毙,則返回 -1 | 從前向后查找 |
arr.lastIndexOf() | 查找某個(gè)元素的索引值 | 若有重復(fù)的,則返回第一個(gè)查到的索引值若不存在,則返回 -1 | 從后往前查找 |
Array.from() | 將偽數(shù)組變成數(shù)組 | 數(shù)組 | 就是只要有l(wèi)ength的就可以轉(zhuǎn)成數(shù)組(ES6) |
Array.of() | 將一組值轉(zhuǎn)換成數(shù)組巨缘,類似于聲明數(shù)組 | 無 | |
arr.copyWithin() | 在當(dāng)前數(shù)組內(nèi)部端三,將制定位置的數(shù)組復(fù)制到其他位置 | 返回當(dāng)前數(shù)組 | 會(huì)覆蓋原數(shù)組項(xiàng) |
arr.findIndex(callback) | 找到第一個(gè)符合條件的數(shù)組成員的索引值 | 無 | |
arr.fill(target, start, end) | 使用給定的值,填充一個(gè)數(shù)組 | 填充完后會(huì)改變?cè)瓟?shù)組 | |
arr.includes() | 判斷數(shù)中是否包含給定的值 | 返回的是布爾值 | 無 |
arr.keys() | 遍歷數(shù)組的鍵名 | 無 | |
arr.values() | 遍歷數(shù)組鍵值 | 無 | |
arr.entries() | 遍歷數(shù)組的鍵名和鍵值 | 無 |
let a = [1,2,3,4];
let b = [1,2,3,4];
let c = [1,2,3,4];
let d = [1,2,3,4];
let e = [1,2,3,4];
let newA = [];
a.forEach(item => {
if (item > 2){
newA.push(item)
}
})
console.log(newA, a);
let newB = b.map(item => {
if (item > 2){
return item
}
})
console.log(newB, b);
let newC = c.filter(item => {
if (item > 2){
return item
}
})
console.log(newC, c)
let D= d.every(item => {
return item > 2
})
console.log(D, d)
let E = e.some(item => {
return item > 2
})
console.log(E, e)
3、原型鏈 new的作用
3.1械蹋、原型鏈
每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象斥滤,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針巷嚣,而實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針。那么假如我們讓原型對(duì)象等于另一個(gè)類型的實(shí)例钳吟,結(jié)果會(huì)怎樣廷粒?顯然,此時(shí)的原型對(duì)象將包含一個(gè)指向另一個(gè)原型的指針砸抛,相應(yīng)地评雌,另一個(gè)原型中也包含著一個(gè)指向另一個(gè)構(gòu)造函數(shù)的指針。假如另一個(gè)原型又是另一個(gè)類型的實(shí)例直焙,那么上述關(guān)系依然成立景东。如此層層遞進(jìn),就構(gòu)成了實(shí)例與原型的鏈條奔誓。這就是所謂的原型鏈的基本概念斤吐。——摘自《javascript高級(jí)程序設(shè)計(jì)》
3.2厨喂、new的作用
1.創(chuàng)建一個(gè)空對(duì)象 p
2.把這個(gè)空對(duì)象 p 的屬性 __proto__ 指向函數(shù) Person 的 prototype
3.將構(gòu)造函數(shù) Person 的作用域賦給新對(duì)象 p和措,即 this 指向了 p
4.執(zhí)行Person 中的代碼,為p添加屬性 name
5.返回新對(duì)象蜕煌。
4派阱、js有哪些作用域 閉包問題 寫防抖函數(shù)
4.1 作用域
1、定義:作用域是在運(yùn)行時(shí)代碼中的某些特定部分中變量斜纪,函數(shù)和對(duì)象的可訪問性贫母。換句話說,能夠訪問另一個(gè)函數(shù)作用域的變量的函數(shù)
2盒刚、全局作用域腺劣、函數(shù)作用域、塊級(jí)作用域(ES6)
4.2 閉包
4.2.1因块、定義
當(dāng)內(nèi)部函數(shù)被保存到外部時(shí)橘原,會(huì)形成閉包;閉包會(huì)導(dǎo)致原始作用域鏈不釋放涡上,造成內(nèi)存泄漏(占用)趾断;
function a() {
var i = '初始值';
i = i + "—_執(zhí)行a"
// 此處的函數(shù)b訪問了父級(jí)函數(shù)a中的局部變量i,成為了一個(gè)閉包
function b() {
i = i + "_執(zhí)行b"
console.log(i)
}
return b;
}
var c = a(); // 此時(shí) i 的值為 :初始值—_執(zhí)行a
c() // 此時(shí) i 的值為 :初始值—_執(zhí)行a_執(zhí)行b
c() // 此時(shí) i 的值為 :初始值—_執(zhí)行a_執(zhí)行b_執(zhí)行b
以上方代碼為例:
- 將函數(shù)a賦值給全局變量c時(shí),a會(huì)執(zhí)行一次吩愧,局部變量 i 的值變?yōu)?code>初始值—_執(zhí)行a芋酌,最終返回函數(shù)b,此時(shí)全局變量c的值為閉包函數(shù)b的引用耻警。
此時(shí)函數(shù)a雖然已執(zhí)行完,但因?yàn)閮?nèi)部包含閉包函數(shù)b,所以函數(shù) a 的執(zhí)行期上下文會(huì)繼續(xù)保留在內(nèi)存中甘穿,不會(huì)被銷毀腮恩,所以局部變量 i 仍是初始值—_執(zhí)行a
執(zhí)行期上下文:當(dāng)函數(shù)執(zhí)行時(shí),會(huì)創(chuàng)建一個(gè)執(zhí)行期上下文的內(nèi)部對(duì)象温兼。每調(diào)用一次函數(shù)秸滴,就會(huì)創(chuàng)建一個(gè)新的上下文對(duì)象,他們之間是相互獨(dú)立的募判。當(dāng)函數(shù)執(zhí)行完畢荡含,它所產(chǎn)生的執(zhí)行期上下文會(huì)被銷毀
- 1、第一次執(zhí)行 c() 時(shí)届垫,閉包函數(shù)b第一次執(zhí)行释液,局部變量 i 的值變?yōu)?code>初始值—_執(zhí)行a_執(zhí)行b
- 2、第二次執(zhí)行 c() 時(shí)装处,閉包函數(shù)b第二次執(zhí)行误债,局部變量 i 的值變?yōu)?code>初始值—_執(zhí)行a_執(zhí)行b_執(zhí)行b
4.2.2、閉包的特點(diǎn)
- 1.被閉包函數(shù)訪問的父級(jí)及以上的函數(shù)的局部變量(如范例中的局部變量 i )會(huì)一直存在于內(nèi)存中妄迁,不會(huì)被JS的垃圾回收機(jī)制回收寝蹈。
- 2.閉包函數(shù)實(shí)現(xiàn)了對(duì)其他函數(shù)內(nèi)部變量的訪問。(函數(shù)內(nèi)部的變量對(duì)外是無法訪問的登淘,閉包通過這種變通的方法箫老,實(shí)現(xiàn)了訪問。)
4.2.3黔州、Javascript的垃圾回收機(jī)制
- 如果一個(gè)對(duì)象不再被引用耍鬓,那么這個(gè)對(duì)象就會(huì)被GC回收。
- 如果兩個(gè)對(duì)象互相引用辩撑,而不再被第三者所引用界斜,那么這兩個(gè)對(duì)象都會(huì)被回收。
eg:
function person(name) {
function say(content) {
console.log(name + ':' + content)
}
return say
}
a = person("張三")
b = person("李四")
a("在干啥合冀?")
b("沒干啥各薇。")
a("出去玩嗎?")
b("去哪熬伞峭判?")
4.2.4、優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
可以減少全局變量的定義棕叫,避免全局變量的污染
能夠讀取函數(shù)內(nèi)部的變量
在內(nèi)存中維護(hù)一個(gè)變量林螃,可以用做緩存缺點(diǎn):
1)造成內(nèi)存泄露
閉包會(huì)使函數(shù)中的變量一直保存在內(nèi)存中,內(nèi)存消耗很大俺泣,所以不能濫用閉包疗认,否則會(huì)造成網(wǎng)頁的性能問題完残,在IE中可能導(dǎo)致內(nèi)存泄露。(解決方法——使用完變量后横漏,手動(dòng)將它賦值為null谨设;)
2)閉包可能在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值缎浇。
3)造成性能損失
由于閉包涉及跨作用域的訪問扎拣,所以會(huì)導(dǎo)致性能損失。
(解決方法——通過把跨作用域變量存儲(chǔ)在局部變量中素跺,然后直接訪問局部變量二蓝,來減輕對(duì)執(zhí)行速度的影響)
4.3、函數(shù)防抖(debounce)
當(dāng)持續(xù)觸發(fā)事件時(shí)指厌,一定時(shí)間段內(nèi)沒有再觸發(fā)事件刊愚,事件處理函數(shù)才會(huì)執(zhí)行一次,如果設(shè)定的時(shí)間到來之前仑乌,又一次觸發(fā)了事件百拓,就重新開始延時(shí)。
實(shí)際場(chǎng)景:
連續(xù)的事件晰甚,只需觸發(fā)一次的回調(diào)場(chǎng)景有:
1衙传、搜索框搜索輸入。
2厕九、只需要用戶最后一次輸入完再發(fā)送請(qǐng)求 手機(jī)號(hào)蓖捶、郵箱格式的輸入驗(yàn)證檢測(cè)
3、窗口大小的resize 扁远。只需窗口調(diào)整完成后俊鱼,計(jì)算窗口的大小,防止重復(fù)渲染
function debounce(fn, wait) {
var timeout = null;
return function() {
if(timeout !== null) clearTimeout(timeout);
timeout = setTimeout(fn, wait);
}
}
// 處理函數(shù)
function handle() {
console.log(Math.random());
}
// 滾動(dòng)事件
window.addEventListener('scroll', debounce(handle, 1000));
//當(dāng)持續(xù)觸發(fā)scroll事件時(shí)畅买,事件處理函數(shù)handle只在停止?jié)L動(dòng)1000毫秒之后才會(huì)調(diào)用一次并闲,也就是說在持續(xù)觸發(fā)scroll事件的過程中,事件處理函數(shù)handle一直沒有執(zhí)行谷羞。
4.4帝火、 函數(shù)節(jié)流(throttle)
當(dāng)持續(xù)觸發(fā)事件時(shí),保證一定時(shí)間段內(nèi)只調(diào)用一次事件處理函數(shù)湃缎。
間隔一段時(shí)間執(zhí)行一次回調(diào)的場(chǎng)景有:
1犀填、滾動(dòng)加載,加載更多或滾動(dòng)到底部監(jiān)聽嗓违;
2九巡、谷歌搜索框,搜索聯(lián)想功能蹂季;
3冕广、高頻點(diǎn)擊提交疏日,表單重復(fù)提交
4、省市信息對(duì)應(yīng)字母快速選擇
//節(jié)流 時(shí)間戳的方式實(shí)現(xiàn)
var throttle = function(func, delay) {
var prev = Date.now();
return function() {
var context = this;
var args = arguments;
var now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));
// 節(jié)流throttle代碼(定時(shí)器):
var throttle = function(func, delay) {
var timer = null;
return function() {
var context = this;
var args = arguments;
if (!timer) {
timer = setTimeout(function() {
func.apply(context, args);
timer = null;
}, delay);
}
}
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));
5撒汉、promise的使用 原理 所擁有的方法
1制恍、Promise 的含義
Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大神凑。它由社區(qū)最早提出和實(shí)現(xiàn),ES6 將其寫進(jìn)了語言標(biāo)準(zhǔn)何吝,統(tǒng)一了用法溉委,原生提供了Promise對(duì)象。
2爱榕、基本用法
ES6 規(guī)定瓣喊,Promise對(duì)象是一個(gè)構(gòu)造函數(shù),用來生成Promise實(shí)例黔酥。
Promise構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù)藻三,該函數(shù)的兩個(gè)參數(shù)分別是resolve(成功)和reject(失敗)跪者。它們是兩個(gè)函數(shù)棵帽,將異步操作的結(jié)果,作為參數(shù)傳遞出去
3渣玲、所擁有的方法
Promise.prototype.catch()
catch方法是.then(null, rejection)的別名逗概,用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)
Promise.prototype.finally()
finally方法用于指定不管 Promise 對(duì)象最后狀態(tài)如何,都會(huì)執(zhí)行的操作
Promise.all()
all方法用于將多個(gè) Promise 實(shí)例忘衍,包裝成一個(gè)新的 Promise 實(shí)例(所有的都成功了才執(zhí)行)
Promise.race()
race方法同樣是將多個(gè) Promise 實(shí)例逾苫,包裝成一個(gè)新的 Promise 實(shí)例
Promise.resolve()
將現(xiàn)有對(duì)象轉(zhuǎn)為 Promise 對(duì)象,Promise.resolve方法就起到這個(gè)作用
Promise.reject()
將現(xiàn)有對(duì)象轉(zhuǎn)為 Promise 對(duì)象枚钓,Promise.reject方法就起到這個(gè)作用(參數(shù)作為reject的理由)
Promise.try()
為所有操作提供了統(tǒng)一的處理機(jī)制,可以更好地管理異常
詳情見http://www.reibang.com/p/d8a901dd72ac
6铅搓、es6有哪些特性 箭頭函數(shù)和普通函數(shù)區(qū)別
1、箭頭函數(shù)
1.1 更簡(jiǎn)潔的語法
1.2 沒有this
1.3 不能使用new 構(gòu)造函數(shù)
1.4 不綁定arguments搀捷,用rest參數(shù)...解決
1.5 使用call()和apply()調(diào)用
1.6 捕獲其所在上下文的 this 值星掰,作為自己的 this 值
1.7 箭頭函數(shù)沒有原型屬性
1.8 不能簡(jiǎn)單返回對(duì)象字面量
1.9 箭頭函數(shù)不能當(dāng)做Generator函數(shù),不能使用yield關(guān)鍵字
1.10 箭頭函數(shù)不能換行
//1、沒有形參的時(shí)候
let fun = () => console.log('我是箭頭函數(shù)');
fun();
//2指煎、只有一個(gè)形參的時(shí)候()可以省略
let fun2 = a => console.log(a);
fun2('aaa');
//3蹋偏、倆個(gè)及倆個(gè)以上的形參的時(shí)候
let fun3 = (x,y) =>console.log(x,y); //函數(shù)體只包含一個(gè)表達(dá)式則省略return 默認(rèn)返回
fun3(24,44);
//4、倆個(gè)形參以及函數(shù)體多條語句表達(dá)式
let fun4 = (x,y) => {
console.log(x,y);
return x+y; //必須加return才有返回值
}
//5至壤、如果要返回對(duì)象時(shí)需要用小括號(hào)包起來威始,因?yàn)榇罄ㄌ?hào)被占用解釋為代碼塊了惋啃,正確寫法
let fun5 = ()=>({ foo: x }) //如果x => { foo: x } //則語法出錯(cuò)
7剩燥、函數(shù)柯里化 純函數(shù)
自己百度吧较鼓, 看不懂鲤看。
http://www.reibang.com/p/2975c25e4d71
8、數(shù)據(jù)不可變 immutable原理
自己百度吧脓斩, 看不懂木西。
https://segmentfault.com/a/1190000016404944
9、js bind函數(shù)的性能問題(https://blog.csdn.net/ywl570717586/article/details/74231402)
10随静、js怎么定義一個(gè)不可改值的對(duì)象
Javascipt的數(shù)據(jù)屬性有一個(gè)名為Writable的特征, 可以用于設(shè)置屬性值是否可以被修改(Object.defineProperty方法接收三個(gè)參數(shù):需要添加或修改屬性的對(duì)象八千,屬性名稱,屬性描述options(writable:false))
11燎猛、const 定義常量可以改變嗎
const所說的常量恋捆,是指,對(duì)應(yīng)的指針或者說地址是常量
const定義的基本數(shù)據(jù)類型的變量不可以修改,但其它復(fù)雜數(shù)據(jù)類型是可以修改的
用const定義的數(shù)組重绷,里面的元素是可變的
如何定義不可改變的數(shù)組:
Object.preventExtendsion(obj) 用來禁止對(duì)象可擴(kuò)展其它屬性(阻止對(duì)象新增屬性沸停,但可改變)
Object.seal(obj)用來禁止對(duì)象刪除其它屬性和擴(kuò)展其它屬性(阻止對(duì)象刪除屬性,但可改變)
Object.freeze(obj)用來凍結(jié)對(duì)象昭卓,就是所有的屬性不能夠更改和新增(阻止對(duì)象更改和新增屬性)
詳情見:https://blog.csdn.net/weixin_33697898/article/details/91371632
12愤钾、深拷貝/淺拷貝
- 1、基本類型--名值存儲(chǔ)在棧內(nèi)存中候醒,例如let a=1;
- 2能颁、引用數(shù)據(jù)類型--名存在棧內(nèi)存中,值存在于堆內(nèi)存中倒淫,但是棧內(nèi)存會(huì)提供一個(gè)引用的地址指向堆內(nèi)存中的值
三劲装、瀏覽器
1、cookie安全
指某些網(wǎng)站為了辨別用戶身份昌简、進(jìn)行session跟蹤而存儲(chǔ)在用戶本地終端上的數(shù)據(jù)(通常經(jīng)過加密)
生命周期:
創(chuàng)建cookie的時(shí)候占业,會(huì)給cookie指定一個(gè)值:Expire,它就是指定cookie的有效期纯赎,也就是cookie的生命周期谦疾,超出設(shè)置的這個(gè)生命周期,cookie就會(huì)被清除犬金。如果給這個(gè)值Expire設(shè)置為0或者負(fù)值念恍,那么這樣的設(shè)置就是在關(guān)閉瀏覽器時(shí),就會(huì)清除cookie晚顷,這種方式更加安全峰伙。
如何解決cookie安全性問題
第一步:設(shè)置cookie有效期不要過長(zhǎng),合適即可
第二步:設(shè)置HttpOnly屬性為true(可以防止js腳本讀取cookie信息该默,有效的防止XSS攻擊)瞳氓。
第三步:設(shè)置復(fù)雜的cookie,加密cookie(盡可能使得加密后的cookie更難解密栓袖,也是保護(hù)了cookie中的信息)
(1)cookie的key使用uuid匣摘,隨機(jī)生成店诗;
(2)cookie的value可以使用復(fù)雜組合,比如:用戶名+當(dāng)前時(shí)間+cookie有效時(shí)間+隨機(jī)數(shù)音榜。
第四步:用戶第一次登錄時(shí)庞瘸,保存ip+cookie加密后的token(每次請(qǐng)求,都去將當(dāng)前cookie和ip組合起來加密后的token與保存的token作對(duì)比赠叼,只有完全對(duì)應(yīng)才能驗(yàn)證成功)
第五步:session和cookie同時(shí)使用(sessionId雖然放在cookie中擦囊,但是相對(duì)的session更安全,可以將相對(duì)重要的信息存入session)
第六步:如果網(wǎng)站支持https嘴办,盡可能使用https(為cookie設(shè)置Secure屬性為true霜第,它的意思是,cookie只能使用https協(xié)議發(fā)送給服務(wù)器户辞,而https比http更加安全)
2、宏任務(wù) 微任務(wù)
setTimeout(() => {
//宏任務(wù)癞谒,放到Event Queue(宏任務(wù)隊(duì)列)中
console.log('1')
});
new Promise((resolve) => {
//主線程底燎,直接執(zhí)行
console.log('2');
resolve();
}).then(() => {
//微任務(wù) 放到Event Queue(微任務(wù)隊(duì)列)中
console.log('3')
});
//主線程,直接執(zhí)行
console.log('4');
執(zhí)行結(jié)果: 2弹砚,4双仍,3,1
解釋如下:
先看執(zhí)行的代碼是同步任務(wù)還是異步任務(wù)桌吃,同步的主線程直接執(zhí)行朱沃,異步任務(wù)放到任務(wù)隊(duì)列中。
任務(wù)隊(duì)列中茅诱,先執(zhí)行一個(gè)宏任務(wù)逗物,若有微任務(wù),執(zhí)行所有的微任務(wù)之后瑟俭,再做新的宏任務(wù)翎卓。
https://www.cnblogs.com/wangziye/p/9566454.html
3、頁面加載過程
- 1摆寄、輸入的網(wǎng)址在通過DNS解析后得到服務(wù)器地址瀏覽器向服務(wù)器發(fā)起http請(qǐng)求失暴,經(jīng)過TCP/IP三次握手確認(rèn)鏈接后,服務(wù)器將需要的代碼發(fā)回給瀏覽器微饥。
- 2逗扒、瀏覽器接收到代碼后進(jìn)行解析,經(jīng)過三大步驟:DOM構(gòu)造欠橘、布局以及繪制頁面
- 2.1矩肩、DOM構(gòu)造
瀏覽器首先將收到的html代碼,通過html解析器解析構(gòu)建為一顆DOM樹肃续。數(shù)據(jù)結(jié)構(gòu)中有許多的樹蛮拔,而DOM樹就像是一顆倒長(zhǎng)著的大樹述暂,這樣的對(duì)象模型決定了節(jié)點(diǎn)之間都有一定的關(guān)聯(lián)它們關(guān)系可能有父子、有兄弟建炫,我們可以順著這顆樹做出許多操作畦韭。
接著將接收到的css代碼,通過css解析器構(gòu)建出樣式表規(guī)則將這些規(guī)則分別放到對(duì)應(yīng)的DOM樹節(jié)點(diǎn)上肛跌,得到一顆帶有樣式屬性的DOM樹艺配。 - 2.2、布局
瀏覽器按從上到下衍慎,從左到右的順序转唉,讀取DOM樹的文檔節(jié)點(diǎn),順序存放到一條虛擬的傳送帶上稳捆。傳送帶上的盒子就是節(jié)點(diǎn)赠法,而這條流動(dòng)的傳送帶就是文檔流。如果我們讀取到的節(jié)點(diǎn)是屬于另一個(gè)節(jié)點(diǎn)下的子節(jié)點(diǎn)乔夯,那么在放入傳送帶的時(shí)候砖织,就應(yīng)該按順序放到該節(jié)點(diǎn)盒子的內(nèi)部。如果子節(jié)點(diǎn)下還有子節(jié)點(diǎn)末荐,在傳送帶上的時(shí)候就繼續(xù)套到子一級(jí)的盒子內(nèi)部侧纯。根據(jù)它在DOM樹上的結(jié)構(gòu),可以嵌套的層級(jí)沒有限制的哦甲脏。文檔流排完之后眶熬,開始獲取計(jì)算節(jié)點(diǎn)的坐標(biāo)和大小等CSS屬性,作為盒子的包裝說明块请。然后把盒子在倉庫里一一擺放娜氏,這就將節(jié)點(diǎn)布局到了頁面。 - 2.3墩新、繪制頁面
布局完成之后牍白,我們?cè)陧撁嫔掀鋵?shí)是看不到任何內(nèi)容的瀏覽器只是計(jì)算出了每一個(gè)節(jié)點(diǎn)對(duì)象應(yīng)該被放到頁面的哪個(gè)位置上,但并沒有可視化抖棘。因此最后一步就是將所有內(nèi)容繪制出來茂腥,完成整個(gè)頁面的渲染。
https://www.zhihu.com/question/30218438
4切省、https ssl加密如何實(shí)現(xiàn)
5最岗、跨域如何解決
- 1、 通過jsonp跨域(jsonp缺點(diǎn):只能實(shí)現(xiàn)get一種請(qǐng)求)
- 2朝捆、 document.domain + iframe跨域(此方案僅限主域相同般渡,子域不同的跨域應(yīng)用場(chǎng)景。)
- 3、 location.hash + iframe
- 4驯用、 window.name + iframe跨域(window.name屬性的獨(dú)特之處:name值在不同的頁面(甚至不同域名)加載后依舊存在脸秽,并且可以支持非常長(zhǎng)的 name 值2MB)
總結(jié):通過iframe的src屬性由外域轉(zhuǎn)向本地域,跨域數(shù)據(jù)即由iframe的window.name從外域傳遞到本地域蝴乔。這個(gè)就巧妙地繞過了瀏覽器的跨域訪問限制记餐,但同時(shí)它又是安全操作。
- 5薇正、 postMessage跨域
postMessage是HTML5 XMLHttpRequest Level 2中的API片酝,且是為數(shù)不多可以跨域操作的window屬性之一,它可用于解決以下方面的問題:
a.) 頁面和其打開的新窗口的數(shù)據(jù)傳遞
b.) 多窗口之間消息傳遞
c.) 頁面與嵌套的iframe消息傳遞
d.) 上面三個(gè)場(chǎng)景的跨域數(shù)據(jù)傳遞
用法
postMessage(data,origin)方法接受兩個(gè)參數(shù)
data: html5規(guī)范支持任意基本類型或可復(fù)制的對(duì)象挖腰,但部分瀏覽器只支持字符串雕沿,所以傳參時(shí)最好用JSON.stringify()序列化。
origin: 協(xié)議+主機(jī)+端口號(hào)猴仑,也可以設(shè)置為"*"审轮,表示可以傳遞給任意窗口,如果要指定和當(dāng)前窗口同源的話設(shè)置為"/"
6辽俗、 跨域資源共享(CORS)
7疾渣、 nginx代理跨域
-
8、 nodejs中間件代理跨域
9榆苞、 WebSocket協(xié)議跨域
https://segmentfault.com/a/1190000011145364
四、框架
4.1霞捡、react
1坐漏、react生命周期,原理碧信,虛擬dom理解赊琳,diff算法原理
2、react版本都更新了什么砰碴,最新版本去掉什么生命周期加入什么生命周期躏筏,為什么
3、組件渲染優(yōu)化
4呈枉、如何理解高階組件
5趁尼、redux理念是什么 單數(shù)據(jù)流如何改變的
6、webpack有哪些配置屬性 原理 插件如何實(shí)現(xiàn)
7猖辫、bable的配置屬于有哪些 瀏覽器兼容性
8酥泞、AST語法樹
9、小程序父子組件通訊啃憎,wepy父子組件通訊
10芝囤、react創(chuàng)建組件的方法(React.createClass React.Component 函數(shù)定義無狀態(tài)組件)
11、react無狀態(tài)組件和pureComponent區(qū)別
12、react什么時(shí)候setstate是同步的(一步操作中調(diào)用)
13悯姊、react組件間怎么通訊---react原生方法(都是事件機(jī)制啊實(shí)在找不到)
14羡藐、react父組件拿子組件ref(this.refs.xxx.refs.textinput)
15、react將組件渲染到指定dom節(jié)點(diǎn)(https://blog.csdn.net/neoveee/article/details/57399834)
16悯许、webpack插件有哪些(extract-text-webpack-plugin單獨(dú)打包c(diǎn)ss)仆嗦,怎么多個(gè)入口,怎么打包成內(nèi)聯(lián)樣式岸晦?欧啤?? 启上,不打包某個(gè)文件邢隧??
17冈在、React如何實(shí)現(xiàn)vue中的插件模式???
react沒有實(shí)際開發(fā)經(jīng)驗(yàn)倒慧,等有經(jīng)驗(yàn)了再整理吧
4.2、vue
9包券、vue的雙向數(shù)據(jù)流如何實(shí)現(xiàn)
vue數(shù)據(jù)雙向綁定是通過數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式的方式來實(shí)現(xiàn)的
Object.defineProperty()
這個(gè)方法重新定義了對(duì)象獲取屬性值(get
)和設(shè)置屬性值(set
)的操作來實(shí)現(xiàn)的纫谅。
var obj = { };
var name;
//第一個(gè)參數(shù):定義屬性的對(duì)象。
//第二個(gè)參數(shù):要定義或修改的屬性的名稱溅固。
//第三個(gè)參數(shù):將被定義或修改的屬性描述符付秕。
Object.defineProperty(obj, "data", {
//獲取值get:
function () { return name; },
//設(shè)置值set:
function (val) {
name = val;
console.log(val)}
})
//賦值調(diào)用
setobj.data = 'aaa';
//取值調(diào)用
getconsole.log(obj.data);
// 代碼演示:defineProperty的雙向綁定
var obj = {};
Object.defineProperty(obj, 'val', {
set: function (newVal) {
document.getElementById("a").value = newVal == undefined ? '' : newVal;
document.getElementById("b").innerHTML = newVal == undefined ? '' : newVal;
}
});
document.getElementById("a").addEventListener("keyup", function (e) {
obj.val = e.target.value;
})
computed 計(jì)算屬性與method方法的區(qū)別
computed中的計(jì)算屬性可以寫在method中,區(qū)別就是method調(diào)用要加()而computed不用
computed中必須要加return
computed里面的方法不是通過事件去觸發(fā)的侍郭,而是當(dāng)屬性(必須是data中的屬性)發(fā)生改變的時(shí)候那么當(dāng)前函數(shù)就會(huì)被觸發(fā)
最大的區(qū)別是询吴,computed中有緩存,相同的值會(huì)直接拿已經(jīng)緩存的亮元,提高性能猛计,但是method沒有緩存,一樣的值還是會(huì)重新獲取
1爆捞、Vue循環(huán)為什么要加key
key屬性可以用來提升v-for渲染的效率奉瘤,vue中使用v-for渲染數(shù)據(jù)的時(shí)候,并不會(huì)去改變?cè)械脑睾蛿?shù)據(jù)煮甥,而是創(chuàng)建新的元素盗温,再把新的數(shù)據(jù)渲染進(jìn)去。
2成肘、Vue循環(huán)為什么不用index作為key
index 作為 key肌访,和沒寫基本上沒區(qū)別,因?yàn)椴还苣銛?shù)組的順序怎么顛倒艇劫,index 都是 0, 1, 2 這樣排列吼驶,導(dǎo)致 Vue 虛擬DOM的復(fù)用會(huì)映射到錯(cuò)誤的舊子節(jié)點(diǎn)惩激,做很多額外的工作,影響效率蟹演。
vue原理 數(shù)據(jù)劫持 路由守衛(wèi)怎么用 axios怎么寫請(qǐng)求攔截 響應(yīng)攔截
10vuex如何數(shù)據(jù)綁定的
11vue有哪些框架優(yōu)缺點(diǎn)
五风钻、Reactnative
1有哪些坑,怎么解決
2熱更新問題
3性能問題酒请,比如列表
4首屏白屏怎么解決
5自己封裝過什么組件
6js和原生通訊方法有哪些 jsbridge原理
Node
1用來做什么
2用過哪些框架
3express如何解決異步問題
4node從哪個(gè)版本開始有Async和Await
5node數(shù)據(jù)流如何理解
6如何理解中間價(jià)
7node如何確保穩(wěn)定性骡技,進(jìn)程死了如何自動(dòng)修復(fù)
六、網(wǎng)絡(luò)
1tcp三次握手
2分析請(qǐng)求頭
算法
1隨機(jī)一個(gè)數(shù)組羞反,數(shù)組每個(gè)值區(qū)間2-32
2最長(zhǎng)回文字段
開放性問題
1flutter有使用過嗎布朦,你感覺如何
2全局有console的地方全部換成彈框顯示
3如何優(yōu)化pc和app
4項(xiàng)目如何發(fā)布部署,如何本地開發(fā)昼窗,git使用等
函數(shù)式編程
函數(shù)式編程(縮寫為 FP)是一種通過組合純函數(shù)來構(gòu)建軟件的過程是趴,避免狀態(tài)共享、可變數(shù)據(jù)及副作用的產(chǎn)生澄惊。
1唆途、函數(shù)式編程定義
2、函數(shù)式編程的特點(diǎn)
- 函數(shù)是"第一等公民"
把它想象成一個(gè)數(shù)據(jù)類型掸驱,可以聲明肛搬、賦值給其他變量、當(dāng)參數(shù)傳給函數(shù)等等
- 函數(shù)是"第一等公民"
- 只用"表達(dá)式"毕贼,不用"語句"
"表達(dá)式"(expression):是一個(gè)單純的運(yùn)算過程温赔,總是有返回值;
"語句"(statement):是執(zhí)行某種操作鬼癣,沒有返回值陶贼。
函數(shù)式編程要求,只使用表達(dá)式扣溺,不使用語句骇窍。也就是說瓜晤,每一步都是單純的運(yùn)算锥余,而且都有返回值。
- 只用"表達(dá)式"毕贼,不用"語句"
- 沒有"副作用"
所謂"副作用"痢掠,指的是函數(shù)內(nèi)部與外部互動(dòng)(最典型的情況驱犹,就是修改全局變量的值),產(chǎn)生運(yùn)算以外的其他結(jié)果足画。
函數(shù)式編程強(qiáng)調(diào)沒有"副作用"雄驹,意味著函數(shù)要保持獨(dú)立,所有功能就是返回一個(gè)新的值淹辞,沒有其他行為医舆,尤其是不得修改外部變量的值。
- 沒有"副作用"
- 不修改狀態(tài)
函數(shù)式編程只是返回新的值,不修改系統(tǒng)變量蔬将。因此爷速,不修改變量,也是它的一個(gè)重要特點(diǎn)霞怀。
- 不修改狀態(tài)
- 引用透明
引用透明(Referential transparency)惫东,指的是函數(shù)的運(yùn)行不依賴于外部變量或"狀態(tài)",只依賴于輸入的參數(shù)毙石,任何時(shí)候只要參數(shù)相同廉沮,引用函數(shù)所得到的返回值總是相同的。
方法傳入的參數(shù)類型與返回值類型是一樣的(類比map徐矩,same方法滞时,傳入一個(gè)數(shù)組同時(shí)返回的也是一個(gè)數(shù)組)
來自:http://www.ruanyifeng.com/blog/2012/04/functional_programming.html
- 引用透明
undenfine 和null 有什么區(qū)別 做if判斷會(huì)怎樣
http://www.ruanyifeng.com/blog/2014/03/undefined-vs-null.html
vue數(shù)據(jù)劫持
- 針對(duì) Object 類型,采用 Object.defineProperty() 方法劫持屬性的讀取和設(shè)置方法丧蘸;
- 針對(duì) Array 類型漂洋,采用原型相關(guān)的知識(shí)劫持常用的函數(shù),從而知曉當(dāng)前數(shù)組發(fā)生變化力喷。
注意: Object.defineProperty() 方法存在以下缺陷:
每次只能設(shè)置一個(gè)具體的屬性刽漂,導(dǎo)致需要遍歷對(duì)象來設(shè)置屬性,同時(shí)也導(dǎo)致了無法探測(cè)新增屬性弟孟;
屬性描述符 configurable 對(duì)其的影響是致命的贝咙。而 ES6 中的 Proxy 可以完美的解決這些問題
raw-loader:加載文件原始內(nèi)容(utf-8)
file-loader:把文件輸出到一個(gè)文件夾中,在代碼中通過相對(duì) URL 去引用輸出的文件 (處理圖片和字體)
url-loader:與 file-loader 類似拂募,區(qū)別是用戶可以設(shè)置一個(gè)閾值庭猩,大于閾值會(huì)交給 file-loader 處理,小于閾值時(shí)返回文件 base64 形式編碼 (處理圖片和字體)
source-map-loader:加載額外的 Source Map 文件陈症,以方便斷點(diǎn)調(diào)試
svg-inline-loader:將壓縮后的 SVG 內(nèi)容注入代碼中
image-loader:加載并且壓縮圖片文件
json-loader 加載 JSON 文件(默認(rèn)包含)
handlebars-loader: 將 Handlebars 模版編譯成函數(shù)并返回
babel-loader:把 ES6 轉(zhuǎn)換成 ES5
ts-loader: 將 TypeScript 轉(zhuǎn)換成 JavaScript
awesome-typescript-loader:將 TypeScript 轉(zhuǎn)換成 JavaScript蔼水,性能優(yōu)于 ts-loader
sass-loader:將SCSS/SASS代碼轉(zhuǎn)換成CSS
css-loader:加載 CSS,支持模塊化录肯、壓縮趴腋、文件導(dǎo)入等特性
style-loader:把 CSS 代碼注入到 JavaScript 中,通過 DOM 操作去加載 CSS
postcss-loader:擴(kuò)展 CSS 語法论咏,使用下一代 CSS优炬,可以配合 autoprefixer 插件自動(dòng)補(bǔ)齊 CSS3 前綴
eslint-loader:通過 ESLint 檢查 JavaScript 代碼
tslint-loader:通過 TSLint檢查 TypeScript 代碼
mocha-loader:加載 Mocha 測(cè)試用例的代碼
coverjs-loader:計(jì)算測(cè)試的覆蓋率
vue-loader:加載 Vue.js 單文件組件
i18n-loader: 國(guó)際化
cache-loader: 可以在一些性能開銷較大的 Loader 之前添加,目的是將結(jié)果緩存到磁盤里
有哪些常見的Plugin厅贪?你用過哪些Plugin蠢护?
define-plugin:定義環(huán)境變量 (Webpack4 之后指定 mode 會(huì)自動(dòng)配置)
ignore-plugin:忽略部分文件
html-webpack-plugin:簡(jiǎn)化 HTML 文件創(chuàng)建 (依賴于 html-loader)
web-webpack-plugin:可方便地為單頁應(yīng)用輸出 HTML,比 html-webpack-plugin 好用
uglifyjs-webpack-plugin:不支持 ES6 壓縮 (Webpack4 以前)
terser-webpack-plugin: 支持壓縮 ES6 (Webpack4)
webpack-parallel-uglify-plugin: 多進(jìn)程執(zhí)行代碼壓縮养涮,提升構(gòu)建速度
mini-css-extract-plugin: 分離樣式文件葵硕,CSS 提取為獨(dú)立文件眉抬,支持按需加載 (替代extract-text-webpack-plugin)
serviceworker-webpack-plugin:為網(wǎng)頁應(yīng)用增加離線緩存功能
clean-webpack-plugin: 目錄清理
ModuleConcatenationPlugin: 開啟 Scope Hoisting
speed-measure-webpack-plugin: 可以看到每個(gè) Loader 和 Plugin 執(zhí)行耗時(shí) (整個(gè)打包耗時(shí)、每個(gè) Plugin 和 Loader 耗時(shí))
webpack-bundle-analyzer: 可視化 Webpack 輸出文件的體積 (業(yè)務(wù)組件懈凹、依賴第三方模塊)
Loader和Plugin的區(qū)別吐辙?
Loader 本質(zhì)就是一個(gè)函數(shù),在該函數(shù)中對(duì)接收到的內(nèi)容進(jìn)行轉(zhuǎn)換蘸劈,返回轉(zhuǎn)換后的結(jié)果昏苏。 因?yàn)?Webpack 只認(rèn)識(shí) JavaScript,所以 Loader 就成了翻譯官威沫,對(duì)其他類型的資源進(jìn)行轉(zhuǎn)譯的預(yù)處理工作贤惯。
Plugin 就是插件,基于事件流框架 Tapable棒掠,插件可以擴(kuò)展 Webpack 的功能孵构,在 Webpack 運(yùn)行的生命周期中會(huì)廣播出許多事件,Plugin 可以監(jiān)聽這些事件烟很,在合適的時(shí)機(jī)通過 Webpack 提供的 API 改變輸出結(jié)果颈墅。
Loader 在 module.rules 中配置,作為模塊的解析規(guī)則雾袱,類型為數(shù)組恤筛。每一項(xiàng)都是一個(gè) Object,內(nèi)部包含了 test(類型文件)芹橡、loader毒坛、options (參數(shù))等屬性。
Plugin 在 plugins 中單獨(dú)配置林说,類型為數(shù)組煎殷,每一項(xiàng)是一個(gè) Plugin 的實(shí)例,參數(shù)都通過構(gòu)造函數(shù)傳入腿箩。
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 有時(shí)我們會(huì)指定打包文件中帶有 hash豪直,那么每次生成的 js 文件名會(huì)有所不同,不能讓我們每次都人工去修改 html珠移,
// 我們可以使用 html-webpack-plugin 插件來幫助我們完成這些事情弓乙。
// 有時(shí)候,我們的腳手架不僅僅給自己使用剑梳,也許還提供給其它業(yè)務(wù)使用唆貌,html 文件的可配置性可能很重要滑潘,比如:你公司有專門的部門提供M頁的公共頭部/公共尾部垢乙,埋點(diǎn)jssdk以及分享的jssdk等等,但是不是每個(gè)業(yè)務(wù)都需要這些內(nèi)容语卤。
// 一個(gè)功能可能對(duì)應(yīng)多個(gè) js 或者是 css 文件追逮,如果每次都是業(yè)務(wù)自行修改 public/index.html 文件酪刀,也挺麻煩的。首先他們得搞清楚每個(gè)功能需要引入的文件钮孵,然后才能對(duì) index.html 進(jìn)行修改骂倘。
// 此時(shí)我們可以增加一個(gè)配置文件,業(yè)務(wù)通過設(shè)置 true 或 false 來選出自己需要的功能巴席,我們?cè)俑鶕?jù)配置文件的內(nèi)容历涝,為每個(gè)業(yè)務(wù)生成相應(yīng)的 html 文件,豈不是美美的漾唉。
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// 每次 clean-webpack-plugin 都會(huì)幫我們先清空一波 dist 目錄的插件
const CopyWebpackPlugin = require('copy-webpack-plugin');
// 靜態(tài)資源拷貝插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 抽離CSS荧库,即將CSS文件單獨(dú)打包的插件,這可能是因?yàn)榇虬梢粋€(gè)JS文件太大赵刑,影響加載速度分衫,也有可能是為了緩存
const OptimizeCssPlugin = require('optimize-css-assets-webpack-plugin');
// 使用 mini-css-extract-plugin,CSS 文件默認(rèn)不會(huì)被壓縮般此,如果想要壓縮蚪战,需要配置 optimization插件
// import() 語法,
// 按需加載
// 需要 @babel/plugin-syntax-dynamic-import 的插件支持铐懊,
// 但是因?yàn)楫?dāng)前 @babel/preset-env 預(yù)設(shè)中已經(jīng)包含了 @babel/plugin-syntax-dynamic-import邀桑,因此我們不需要再單獨(dú)安裝和配置。
const webpack = require('webpack');
const path = require('path');
const isDev = process.env.NODE_ENV === 'development';
const config = require('./public/config')[isDev ? 'dev' : 'build'];
module.exports = {
mode: isDev ? 'development' : 'production',
// mode 配置項(xiàng)科乎,告知 webpack 使用相應(yīng)模式的內(nèi)置優(yōu)化概漱。
// mode 配置項(xiàng),支持以下兩個(gè)配置:
// development:將 process.env.NODE_ENV 的值設(shè)置為 development喜喂,啟用 NamedChunksPlugin 和 NamedModulesPlugin
// production:將 process.env.NODE_ENV 的值設(shè)置為 production瓤摧,啟用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin
entry: {
index: './src/index.js',
login: './src/login.js'
},
// entry 的值可以是一個(gè)字符串,一個(gè)數(shù)組或是一個(gè)對(duì)象玉吁。
// 字符串的情況無需多說照弥,就是以對(duì)應(yīng)的文件為入口。
// 為數(shù)組時(shí)进副,表示有“多個(gè)主入口”这揣,想要多個(gè)依賴文件一起注入時(shí)
output: {
path: path.resolve(__dirname, 'dist'), //必須是絕對(duì)路徑
filename: 'bundle.[hash:6].js',
publicPath: '/' //通常是CDN地址
},
// 例如,你最終編譯出來的代碼部署在 CDN 上影斑,資源的地址為: 'https://AAA/BBB/YourProject/XXX'给赞,那么可以將生產(chǎn)的 publicPath 配置為: //AAA/BBB/。
// 編譯時(shí)矫户,可以不配置片迅,或者配置為 /〗粤桑可以在我們之前提及的 config.js 中指定 publicPath(config.js 中區(qū)分了 dev 和 public)柑蛇, 當(dāng)然還可以區(qū)分不同的環(huán)境指定配置文件來設(shè)置芥挣,或者是根據(jù) isDev 字段來設(shè)置。
module: {
// loader 讓 webpack 能夠去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)耻台,用于對(duì)源代碼進(jìn)行轉(zhuǎn)換
rules: [
{
test: /\.jsx?$/, //匹配規(guī)則空免,針對(duì)符合規(guī)則的文件進(jìn)行處理。
use: {
loader: 'babel-loader',
options: { //這里盆耽,我們可以在 .babelrc 中編寫 babel 的配置蹋砚,也可以在 webpack.config.js 中進(jìn)行配置。
presets: ["@babel/preset-env"],
plugins: [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3
}
]
]
}
},
exclude: /node_modules/ //排除 node_modules 目錄
},
// 講js轉(zhuǎn)譯為低版本
{
test: /.html$/,
use: 'html-withimg-loader'
},
// 處理在html中引入的本地圖片
// use 字段有幾種寫法
// 可以是一個(gè)字符串摄杂,例如上面的 use: 'html-withimg-loader'
// use 字段可以是一個(gè)數(shù)組都弹,例如處理CSS文件時(shí),use: ['style-loader', 'css-loader']
// use 數(shù)組的每一項(xiàng)既可以是字符串也可以是一個(gè)對(duì)象匙姜,當(dāng)我們需要在webpack 的配置文件中對(duì) loader 進(jìn)行配置畅厢,就需要將其編寫為一個(gè)對(duì)象,
// 并且在此對(duì)象的 options 字段中進(jìn)行配置氮昧。
// loader 的執(zhí)行順序是從右向左執(zhí)行的框杜,也就是后面的 loader 先執(zhí)行,下面 loader 的執(zhí)行順序?yàn)? less-loader ---> postcss-loader ---> css-loader ---> style-loader
// 當(dāng)然袖肥,loader 其實(shí)還有一個(gè)參數(shù)咪辱,可以修改優(yōu)先級(jí),enforce 參數(shù)椎组,其值可以為: pre(優(yōu)先執(zhí)行) 或 post (滯后執(zhí)行)油狂。
{
test: /\.(le|c)ss$/,
use: [
// 'style-loader',
MiniCssExtractPlugin.loader, //替換之前的 style-loader
'css-loader', {
loader: 'postcss-loader',
options: {
plugins: function () {
return [
require('autoprefixer')()
]
}
}
}, 'less-loader'],
exclude: /node_modules/
},
// style-loader 動(dòng)態(tài)創(chuàng)建 style 標(biāo)簽,將 css 插入到 head 中.
// css-loader 負(fù)責(zé)處理 @import 等語句寸癌。
// postcss-loader 和 autoprefixer专筷,自動(dòng)生成瀏覽器兼容性前綴
// less-loader 負(fù)責(zé)處理編譯 .less 文件,將其轉(zhuǎn)為 css
{
test: /\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240, //10K
esModule: false,
outpath:'assets'
}
}
],
exclude: /node_modules/
},
// 我們可以使用 url-loader 或者 file-loader 來處理本地的資源文件。
// url-loader 和 file-loader 的功能類似蒸苇,
// 但是 url-loader 可以指定在文件大小小于指定的限制時(shí)磷蛹,返回 DataURL,
// 因此溪烤,個(gè)人會(huì)優(yōu)先選擇使用 url-loader
// 當(dāng)本地資源較多時(shí)味咳,我們有時(shí)會(huì)希望它們能打包在一個(gè)文件夾下,這也很簡(jiǎn)單檬嘀,我們只需要在 url-loader 的 options 中指定 outpath槽驶,如: outputPath: 'assets'
// 此處設(shè)置 limit 的值大小為 10240,即資源大小小于 10K 時(shí)鸳兽,將資源轉(zhuǎn)換為 base64掂铐,超過 10K,將圖片拷貝到 dist 目錄。
// esModule 設(shè)置為 false堡纬,否則,<img src={require('XXX.jpg')} /> 會(huì)出現(xiàn) <img src=[Module Object] />
// 將資源轉(zhuǎn)換為 base64 可以減少網(wǎng)絡(luò)請(qǐng)求次數(shù)蒿秦,但是 base64 數(shù)據(jù)較大烤镐,如果太多的資源是 base64,會(huì)導(dǎo)致加載變慢棍鳖,
// 因此設(shè)置 limit 值時(shí)炮叶,需要二者兼顧。
]
},
devtool: isDev ? 'cheap-module-eval-source-map' : 'source-map',
// devtool 中的一些設(shè)置渡处,可以幫助我們將編譯后的代碼映射回原始源代碼镜悉。不同的值會(huì)明顯影響到構(gòu)建和重新構(gòu)建的速度郭变。
// 能夠定位到源碼的行即可暑劝,因此,綜合構(gòu)建速度印屁,在開發(fā)模式下醇份,設(shè)置 devtool 的值是 cheap-module-eval-source-map稼锅。
// 生產(chǎn)環(huán)境可以使用 none 或者是 source-map,使用 source-map 最終會(huì)單獨(dú)打包出一個(gè) .map 文件僚纷,我們可以根據(jù)報(bào)錯(cuò)信息和此 map 文件矩距,進(jìn)行錯(cuò)誤解析,定位到源代碼怖竭。
// source-map 和 hidden-source-map 都會(huì)打包生成單獨(dú)的 .map 文件锥债,區(qū)別在于,source-map 會(huì)在打包出的js文件中增加一個(gè)引用注釋痊臭,以便開發(fā)工具知道在哪里可以找到它哮肚。hidden-source-map 則不會(huì)在打包的js中增加引用注釋。
// 但是我們一般不會(huì)直接將 .map 文件部署到CDN广匙,因?yàn)闀?huì)直接映射到源碼绽左,更希望將.map 文件傳到錯(cuò)誤解析系統(tǒng),然后根據(jù)上報(bào)的錯(cuò)誤信息艇潭,直接解析到出錯(cuò)的源碼位置拼窥。
plugins: [
//數(shù)組 放著所有的webpack插件
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html', //打包后的文件名
config: config.template, //讀取config配置文件生成不同的文件
// hash: true //是否加上hash,默認(rèn)是 false
chunks: ['index'] //配置此參數(shù)僅會(huì)將數(shù)組中指定的js引入到html文件中蹋凝,此外鲁纠,如果你需要引入多個(gè)JS文件,僅有少數(shù)不想引入鳍寂,還可以指定 excludeChunks 參數(shù)改含,它接受一個(gè)數(shù)組。
}),
new HtmlWebpackPlugin({
template: './public/login.html',
filename: 'login.html', //打包后的文件名
chunks: ['login']
}),
// 多頁面應(yīng)用打包
// 如果需要配置多個(gè) HtmlWebpackPlugin迄汛,
// 那么 filename 字段不可缺省捍壤,否則默認(rèn)生成的都是 index.html骤视,
// 如果你希望 html 的文件名中也帶有 hash,那么直接修改 fliename 字段即可鹃觉,例如: filename: 'login.[hash:6].html'专酗。
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns:['**/*', '!dll', '!dll/**'] //不刪除dll目錄下的文件
}),
new CopyWebpackPlugin({
patterns: [
{
from: 'public/js/*.js', //將 public/js 目錄拷貝至 dist/js 目錄
to: path.resolve(__dirname, 'dist', 'js'),
flatten: true, //設(shè)置為 true,那么它只會(huì)拷貝文件盗扇,而不會(huì)把文件夾路徑都拷貝上祷肯,
// ignore: ['other.js'] 忽略掉 js 目錄下的 other.js 文件
}
],
}),
new MiniCssExtractPlugin({
filename: 'css/[name].css'
//個(gè)人習(xí)慣將css文件放在單獨(dú)目錄下
//publicPath:'../' //如果你的output的publicPath配置的是 './' 這種相對(duì)路徑,那么如果將css文件放在單獨(dú)目錄下疗隶,記得在這里指定一下publicPath
}),
new OptimizeCssPlugin(), //壓縮css插件
new webpack.HotModuleReplacementPlugin(), //熱更新插件
new webpack.DefinePlugin({ //定義環(huán)境變量插件 \
DEV: JSON.stringify('dev'), //字符串
//index.js
// if(DEV === 'dev') {
// //開發(fā)環(huán)境
// }else {
// //生產(chǎn)環(huán)境
// }
FLAG: 'true' //FLAG 是個(gè)布爾類型
})
],
devServer: {
// port: '8888', //默認(rèn)是8080
// quiet: false, //默認(rèn)不啟用
// inline: true, //默認(rèn)開啟 inline 模式佑笋,如果設(shè)置為false,開啟 iframe 模式
// stats: "errors-only", //終端僅打印 error
// overlay: false, //默認(rèn)不啟用
// clientLogLevel: "silent", //日志等級(jí)
// compress: true //是否啟用 gzip 壓縮
hot:true //熱更新
},
// 啟用 quiet 后,除了初始啟動(dòng)信息之外的任何內(nèi)容都不會(huì)被打印到控制臺(tái)斑鼻。這也意味著來自 webpack 的錯(cuò)誤或警告在控制臺(tái)不可見 ,不建議開啟
// stats: "errors-only" 蒋纬,終端中僅打印出 error,注意當(dāng)啟用了 quiet 或者是 noInfo 時(shí)坚弱,此屬性不起作用颠锉。
// 啟用 overlay 后,當(dāng)編譯出錯(cuò)時(shí)史汗,會(huì)在瀏覽器窗口全屏輸出錯(cuò)誤琼掠,默認(rèn)是關(guān)閉的。
resolve: {
modules: ['./src/components', 'node_modules'], //從左到右依次查找
// resolve 配置 webpack 如何尋找模塊所對(duì)應(yīng)的文件停撞。
// webpack 內(nèi)置 JavaScript 模塊化語法解析功能瓷蛙,默認(rèn)會(huì)采用模塊化標(biāo)準(zhǔn)里約定好的規(guī)則去尋找,但你可以根據(jù)自己的需要修改默認(rèn)的規(guī)則戈毒。
extensions: ['web.js', '.js'] //當(dāng)然艰猬,你還可以配置 .json, .css
// extensions適配多端的項(xiàng)目中,可能會(huì)出現(xiàn) .web.js, .wx.js埋市,例如在轉(zhuǎn)web的項(xiàng)目中冠桃,我們希望首先找 .web.js,如果沒有道宅,再找 .js食听。我們可以這樣配置
}
}
// 區(qū)分不同的環(huán)境
// 目前為止我們 webpack 的配置,都定義在了 webpack.config.js 中污茵,對(duì)于需要區(qū)分是開發(fā)環(huán)境還是生產(chǎn)環(huán)境的情況樱报,
// 我們根據(jù) process.env.NODE_ENV 去進(jìn)行了區(qū)分配置,但是配置文件中如果有多處需要區(qū)分環(huán)境的配置泞当,這種顯然不是一個(gè)好辦法迹蛤。
// 更好的做法是創(chuàng)建多個(gè)配置文件,如: webpack.base.js、webpack.dev.js盗飒、webpack.prod.js嚷量。
// 然后修改我們的 package.json,指定對(duì)應(yīng)的 config 文件
// webpack.base.js 定義公共的配置
// webpack.dev.js:定義開發(fā)環(huán)境的配置
// webpack.prod.js:定義生產(chǎn)環(huán)境的配置
// webpack-merge 專為 webpack 設(shè)計(jì)逆趣,提供了一個(gè) merge 函數(shù)蝶溶,用于連接數(shù)組,合并對(duì)象汗贫。
// const merge = require('webpack-merge');
// merge({
// devtool: 'cheap-module-eval-source-map',
// module: {
// rules: [
// {a: 1}
// ]
// },
// plugins: [1,2,3]
// }, {
// devtool: 'none',
// mode: "production",
// module: {
// rules: [
// {a: 2},
// {b: 1}
// ]
// },
// plugins: [4,5,6],
// });
// //合并后的結(jié)果為
// {
// devtool: 'none',
// mode: "production",
// module: {
// rules: [
// {a: 1},
// {a: 2},
// {b: 1}
// ]
// },
// plugins: [1,2,3,4,5,6]
// }