1. HTML
1. 必考:你是如何理解 HTML 語義化的?
荒野階段:最開始是 PHP 后端寫 HTML故黑,不會 CSS傀广,于是就用 table 來布局。table 使用展示表格的翘单。嚴重違反了 HTML 語義化吨枉,索然很快就會寫出頁面,但是后期維護很麻煩哄芜。
美工階段:后來有了專門的寫 CSS 貌亭、html 的前端,他們只會使用 DIV + CSS 布局认臊,主要是用 float 和絕對定位布局圃庭。稍微符合一點,但還是不夠語義化,因為不知道每個div什么意思剧腻,其實是對于第一種方法的換湯不換藥的做法拘央。
前端階段:再后來,前端越來越專業(yè)化书在,知道 HTML 的各個標簽的用法灰伟,于是會使用恰當?shù)臉撕瀬碚故緝?nèi)容,而不是傻傻的全用 div儒旬,會盡量使用標題用 h1~h6栏账、列表用ul/ol>li、段落用 p栈源、導航欄用header, 側(cè)邊欄用aside,底部用footer挡爵,鏈接用a標簽,圖片用img等等標簽分別表示不同的意思凉翻。目前我們寫頁面的就是html語義化標簽了讨。
語義化的好處是易讀、有利于SEO等制轰。
2.meta viewport 是做什么用的前计,怎么寫?
這個標簽是控制頁面在移動端不要縮小顯示垃杖。具體寫法是<meta name=viewport content="width=divice-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0">
一開始男杈,所有頁面都是給PC準備的,喬布斯推出 iPhone 3GS调俘,頁面是不適應(yīng)手機屏幕的伶棒,所以喬布斯的工程師想了一個辦法,默認把手機模擬成 980px彩库,頁面縮小肤无。
后來,智能手機普及骇钦,這個功能在部分網(wǎng)站不需要了宛渐,所以我們就用 meta:vp 讓手機不要縮小我的網(wǎng)頁。
3.你用過哪些 HTML 5 標簽眯搭?
最常見的有:
內(nèi)容相關(guān)的:header/main/footer/article等
-
功能相關(guān)的:canvas/video.audio等
* canvas繪制(的用法等):mdn,首先獲取canvas,然后獲取它的二維上下文窥翩,在設(shè)置筆的顏色最后設(shè)置筆刷的范圍,就能繪圖了鳞仙。 * mdn,添加視頻 video標簽 用到的屬性有:<video src="xx.ogg" autoplay poster="posterimg.jpg" >//想用自己喜歡的播放器看可以加a <a href="xxx.ogg">下載</a> //還可以加字幕:<track></vodeo> * mdn, 添加音頻 audio 屬性和video的差不多
4.H5 是什么寇蚊?
移動端頁面就叫做H5,注意注意棍好!html5是一項標準仗岸,而H5是是一門技術(shù)允耿,他倆不是一個概念。
2. CSS
1. 必考:兩種盒模型分別說一下
- border-box怪異(IE)和模型: width = padding + content + border
- content-box標準盒模型:width = content
高度和寬度類似扒怖。
兩種盒模型比較:正常情況下都用border-box,原因:border-box寫起來更方便右犹。
2. 必考:如何居中?
- 水平居中:
- 塊級元素:
- 內(nèi)聯(lián)元素:
- 垂直居中:
- parent沒有指定高度:child垂直居中方法:padding :10px 0;
- parent 的 height 寫死了姚垃,就很難把 .child 居中念链,以下是垂直居中的七種方法:
1. table自帶功能:【http://js.jirengu.com/gaquk/2/】
2. 100%高度的after before 加上inline-block: 【http://js.jirengu.com/poveg/1/】【http://js.jirengu.com/poveg/3/】
3. div裝成table: 【http://js.jirengu.com/yusux/6/】
4. margin-top:-50%:【http://js.jirengu.com/sugex/1/】
5. translate: -50%: 【http://js.jirengu.com/sugex/3/】
6. absolute margin-auto : 【http://js.jirengu.com/sugex/5/】
7. flex布局:【http://js.jirengu.com/sugex/7/】
3. 考:flex 怎么用,常用屬性有哪些积糯?
Flex是Flexible Box的縮寫掂墓,意為”彈性布局”,用來為盒狀模型提供最大的靈活性看成。Flex布局有兩層,采用flex布局的元素稱為flex容器,其子元素則自動成flex item,即項目.
-
flex容器屬性:
flex-direction:決定項目的排列方向君编。 flex-wrap:即一條軸線排不下時如何換行。 flex-flow:是flex-direction屬性和flex-wrap屬性的簡寫形式川慌,默認值為row nowrap吃嘿。 justify-content:定義了項目在主軸上的對齊方式。(justify) align-items:定義項目在交叉軸上如何對齊梦重。 align-content:定義了多根軸線的對齊方式兑燥。如果項目只有一根軸線,該屬性不起作用琴拧。(換行會產(chǎn)生多軸)
flex-item屬性:
order:定義項目的排列順序降瞳。數(shù)值越小,排列越靠前蚓胸,默認為0挣饥。
flex-grow:定義項目的放大比例,如果所有項目的flex-grow屬性都為1,則它們將等分剩余空間(如果有的話)沛膳。如果一個項目的flex-grow屬性為2扔枫,其他項目都為1,則前者占據(jù)的剩余空間將比其他項多一倍锹安。
flex-shrink:定義了項目的縮小比例短荐,默認為1,如果所有項目的flex-shrink屬性都為1八毯,當空間不足時搓侄,都將等比例縮小瞄桨。如果一個項目的flex-shrink屬性為0话速,其他項目都為1,則空間不足時芯侥,前者不縮小泊交。
flex-basis:定義了在分配多余空間之前乳讥,項目占據(jù)的主軸空間(main size)。
flex:是flex-grow, flex-shrink 和 flex-basis的簡寫廓俭,默認值為0 1 auto云石。后兩個屬性可選。
align-self:允許單個項目有與其他項目不一樣的對齊方式研乒,可覆蓋align-items屬性汹忠。默認值為auto,表示繼承父元素的align-items屬性雹熬,如果沒有父元素宽菜,則等同于stretch。
舉例子問題:在行欄中竿报,最左邊是一個按鈕铅乡,右邊有兩個按鈕
實現(xiàn)方法:
<box>
<item>logo<item>
<item>登錄<item>
<item>注冊<item>
</box>
<style>
box{
display:flex;
justify-content:space-between;
}
item:nth-child(2){
margin-left:auto;
}
</style>
4.必考:BFC 是什么?
中文翻譯:塊級格式化上下文烈菌,舉個例子:我如果給一個div添加overflow:hidden;那么它里面的浮動元素就會被包裹起來阵幸。
- 舉例(抽象問題具體化:不能直接回答B(yǎng)FC是什么,而是舉含有BFC的例子):
- overflow:hidden;是清楚浮動芽世,但是不建議使用這個清楚浮動挚赊,而是用 .clearfix{}來清楚浮動
- overflow:hidden;消除父子margin 合并。
5. CSS 選擇器優(yōu)先級
選擇器優(yōu)先級的說法 class第一位济瓢,id第二位咬腕,……是錯的,在css2時帶還能用葬荷,但是目前css3時帶是不能用涨共。【注意】如果hr引導你往這個錯誤的方向宠漩,那就說這個举反。
1. 越具體優(yōu)先級越高
2. 寫在后面的覆蓋寫在前面的
3. !important的優(yōu)先級最高,但是建議少用
6. 清除浮動說一下(背代碼)
- .clearfix{
content:'';
display:block/table;
clear:both;
}
把這個clearfix加到容器上扒吁,里面的子元素的浮動就被清楚了
3.原生 js
1. 必考:ES 6 語法知道哪些火鼻,分別怎么用?
1. 作用域:
- var 聲明的變量沒有塊級作用域m在語句塊里聲明的變量作用域是其所在的函數(shù)或者 script 標簽內(nèi)雕崩,你可以在語句塊外面訪問到它魁索。
- let : 聲明塊級變量,是有塊級作用域的粗蔚,而且不能重復聲明鹏控。在處理構(gòu)造函數(shù)的時候,可以通過let聲明而不是閉包來創(chuàng)建一個或多個私有成員抖僵。
- const:聲明塊級變量耍群,是有塊級作用域的找筝,常量的值不能通過重新賦值來改變呻征,并且不能重新聲明。
2. 箭頭函數(shù):
- 箭頭函數(shù)的語法比函數(shù)表達式更簡潔沐祷,沒有自己的this\arguments等攒岛,箭頭函數(shù)更適用于那些需要匿名函數(shù)的地方赖临,并且不能用作構(gòu)造函數(shù)。箭頭函數(shù)只有IE瀏覽器不能兼容灾锯。
- sum = (a, b) => a + b
- nums.forEach( v => { console.log(v) })
3. 模板字符串:
1. 實現(xiàn)多行字符串:
```
console.log(`string text line 1
string text line 2`)
```
- 插入表達式:
var a = 10; var b = 5; console.log(`Fifteen is ${a + b } and not ${a * b} `)
4. 解構(gòu)賦值:可以將屬性/值從對象/數(shù)組中取出,賦值給其他變量兢榨,對象或數(shù)組諸葛對應(yīng)值或表達式。
- 結(jié)構(gòu)數(shù)組:
[a,b] = [10,20]
console.log(a); //10
console.log(b); //20
[a,b,...rest] = [10,20,30,40,50]
console.log(rest); //[30,40,50]
- 交換變量:
var a = 10;
var b = 20;
[a,b] = [b,a];
- 用正則表達式匹配提取值:用正則表達式的 exec()方法匹配字符串會返回一個數(shù)組顺饮,該數(shù)組第一個值是完全匹配正則表達式的字符串吵聪,然后的值是匹配正則表達式括號內(nèi)內(nèi)容部分。解構(gòu)賦值允許你輕易地提取出需要的部分兼雄,忽略完全匹配的字符串——如果不需要的話吟逝。
function parseProtocol(url) {
var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
if (!parsedURL) {
return false;
}
console.log(parsedURL); // ["https://developer.mozilla.org/en-US/Web/JavaScript", "https", "developer.mozilla.org", "en-US/Web/JavaScript"]
var [, protocol, fullhost, fullpath] = parsedURL;
return protocol;
}
console.log(parseProtocol('https://developer.mozilla.org/en-US/Web/JavaScript')); // "https"
- 結(jié)構(gòu)對象:
//基本賦值
var obj = {p:42,q:true}
var {p.q} = obj
console.log(p) //42
console.log(q) //true
//無聲明賦值
var a,b;
({a,b} = {a:1,b:2})
- 對象解構(gòu)中的 Rest
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}
a; // 10
b; // 20
rest; // { c: 30, d: 40 }
5. 模塊
1.導入:import:
- 靜態(tài)的inport語句帶入由另一個模板導出的綁定
//語法(必須在嚴格模式下,type='module'的script標簽中使用)
import defaultExport from "Moudule-name"
- 類似于函數(shù)的動態(tài) import(),它不需要依賴
type="module"
的script標簽赦肋。
在 script 標簽中使用nomodule
屬性块攒,可以確保向后兼容
let module = await import('/modules/my-module.js')
- 導出:export:在創(chuàng)建 javascript 模塊時,export語句從模塊中導出函數(shù)佃乘、對象或原始值囱井,以便其他程序通過import 導入并使用他們。
//導出單個單個特性
export let name1,name2,...,nameN;(var const 一樣)
export function FunName(){}
export class ClassName{}
//導出列表
export {name1,name2,...,nameN}
//重命名導出
export {Variable1 as name1,variable2 as name2,...,namwN}
- 默認導出:export default
export default expression
export default function(){}
export default function name1(…) { … } // also class, function*
export { name1 as default, … };
4.模塊重定向
export {defaullt} from './other-module';
exprt * from './other-module';
6.class 類 :類其實是一個特殊的函數(shù)庞呕,類語法糖有兩個部分組成:類表達式和類聲明
- 類聲明:不像函數(shù)聲明,類聲明不會聲明提升澎羞,所以需要先聲明,否則返回一個ReferenceError
class Rectangle{
constructor(width,height){
this.width = width;
this.height = height;
}
}
- 類表達式:
//匿名類:
let Rectangle = class {
constructor(width,height){
this.width = width;
this.height = height;
}
}
//具名類
let Rectangle = class Rectangle{
constructor(width,height){
this.width = width;
this.height = height;
}
}
- 使用extends創(chuàng)建子類(注意:如果在子類中使用構(gòu)造函數(shù)則在使用之前調(diào)用super())
class Animal{
constructor(){
this.name = name
}
speak(){
console.log(this.name + 'makes a noise')
}
}
class Dog extends Animal{
speak(){
console.log(this.name + 'barks')
}
}
var dog = new Dog('mike');
dog.speak();//mike barks
- 也可以繼承傳統(tǒng)的基于函數(shù)的類
function Animal(name){
this.name = name
}
Animal.prototype.speak = function (){
console.log(this.name + 'make a noise')
}
class Dog extends Animal{
speak(){
console.log(this.name + 'barks')
}
}
var dog = new Dog('mike')
dog.speak(); //mike barks
- 調(diào)用超類
class Cat{
constructor(name){
this.name = name
}
speak(){
console.log(this.name + 'makes a noise')
}
}
class Lion extends Cat{
speak(){
super.speak();
console.log(this.name + 'roars')
}
}
7.迭代器
for of VS for in :
這兩個語句都是迭代一些東西;
for in 以任意順序迭代對象的(synbol以外的)可枚舉屬性;
for of 遍歷可迭代對象要迭代的數(shù)據(jù)技羔。
- 一句話總結(jié):for of 遍歷的結(jié)果是值,for in 遍歷的結(jié)果是索引。
- 舉例一:
let arr = ["Apple","Samsung","Nokia","Xiaomi"];
for (let value of arr){
console.log(value)
}
// Apple Samsung Nokia Xiaomi
for (let x in arr){
cosnole.log(x)
}
// 0 1 2 3
- 舉例二:
let obj = { Apple:"iPhone X", Samsung:"Galaxy 6", Nokia:"Lumia",Xiaomi:"Note 3" }
for(let x of obj){
console.log(x)
}
// !! 這樣就報錯了(obj is not iterable)原因是這個對象的值的索引必須是可迭代的
for(let x in obj){
console.log(x)
}
// Apple Samsung Nokia Xiaomi
- 舉例三:
// for-of 遍歷可以迭代的任意對象标沪。而 for-in 遍歷的是必需有明確索引的對象
function* company(){
yield 'Apple';
yield 'Samsung';
yield 'Nokia';
yield 'Xiaomi';
}
for(let x of company()){
console.log(x)
}
// Apple Samsung Nokia Xiaomi
for(let x in company()){
console.log(x)
}
// !! 這將什么都不會輸出
- 總結(jié):for of 遍歷的結(jié)果是值,并且被遍歷的對象必須是可以迭代的,for in 遍歷的結(jié)果是索引坞靶,并且這個索引必須是明確的。
8.Symbol :
ES5的屬性名都是字符串尿这,容易造成屬性名沖突碟摆,ES6引進了一種新的原始數(shù)據(jù)類型:Symbol,表示獨一無二值(每個從Symbol()返回的symbol值都是唯一的)。
Symbol函數(shù)可以接受一個字符串作為參數(shù),表示對Symbol實例的描述轩缤,主要是為了在控制臺顯示,或者轉(zhuǎn)為字符串時,比較容易區(qū)分假瞬。
它每次都會創(chuàng)建一個新的 symbol類型:
//沒有參數(shù)的情況
var s1 = Symbol();
var s2 = Symbol();
s1 === s2 //false
//有參數(shù)的情況下:
var s1 = Symbol('foo');
var s2 = Symbol('foo');
s1 === s2 //false
2. 必考 Promise、Promise.all琴许、Promise.race 分別怎么用?
promise對象用于返回一個異步操作的最終完成結(jié)果。
-
promise對象使用方法:
- .then方法:
$.ajax(……).then(成功函數(shù)辩块,失敗函數(shù)) - 鏈式 .then方法:
$.ajax(……).then(成功函數(shù),失敗函數(shù)).then(成功函數(shù)2液兽,失敗函數(shù)2)
- .then方法:
如何自己生成promise對象:
function fn(){
return new Promise((resolve, reject)=>{
成功時調(diào)用 resolve(數(shù)據(jù))
失敗時調(diào)用 reject(錯誤)
})
}
fn().then(success, fail).then(success2, fail2)
- Promise.all()的用法:
promise.all(iterable)方法返回一個promise實例桃漾,其參數(shù)iterable是可迭代對象适滓,接受一個或多個值的數(shù)組(比如,立即值、promise鱼鸠、thenable)。它返回一個promise麻蹋,此方法在集合多個 promise 的返回結(jié)果時很有用专肪。
舉例:promise1和promise2都成功才會調(diào)用success1
Promise.all([promise1, promise2]).then(success1, fail1)
- promise.race()的用法:顧名思義深夯,Promise.race就是賽跑的意思,意思就是說滓玖,promise1和promise2只要有一個成功就會調(diào)用success1,不管結(jié)果本身是成功還是失敗狀態(tài)。所接受的參數(shù)是一樣的禁悠,接收多個值的數(shù)組隶糕。
Promise.race([promise1, promise2]).then(success1, fail1)
3. 手寫函數(shù)防抖和函數(shù)節(jié)流
- 函數(shù)節(jié)流:可以理解為CD冷卻時間(就是在指定時間段內(nèi)不能執(zhí)行函數(shù)):
function fn(){}
CD = false
button.oncLick = function(){
if(CD){
}else{
fn()
CD = true
var timerId = setTimeout(()=>{
CD = false
} ,3000)
}
}
- 防抖函數(shù):簡單理解為把任務(wù)帶著一起做濒旦,比如說我是一個送外賣的,然后規(guī)定如果定了一個外賣就再等5分鐘,如果來了繼續(xù)再等5分鐘慷荔,如果5分鐘之內(nèi)沒來過就開始把積累的外賣都送。
function fn(){}
var timerId = null
button.onclick = function(){
if(timerId){
window.clearTimeout(timerId)
}
fn()
timerId = null
timerId = setTimeout(()=>{
timerId = null
},5000)
}
}
4. 必考:手寫AJAX(背誦代碼)
function get/post(url,data,callback){
var xhr = new XMLHttpRequest()
xhr.open('POST',"/xxx")
xhr.setRequestHeader("Content-type":"application/x-www-form-url-encoded")
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.response.Status === 200 || xhr.status === 304){
callback(response)
}
}
xhr.send("a = 1 & b = 2")
}
5. 考:這段代碼里的 this 是什么?
函數(shù)里的this就看函數(shù)是怎么調(diào)用的:
- fn() 在正常情況下:window;在'use strict'下:undefined
- obj.fn() this =>obj
- fn.call(xx) this=>xx
- fn.appy(xx) this => xx
- fn.bind(xx) this=> xx
- new Fn() this=>新的對象(生成的實例)
- fn = () => {} this=>外面的的this
6螟蒸, 必考:閉包/立即執(zhí)行函數(shù)是什么?
- 閉包是什么诵原?
由于在JS中,變量的作用域?qū)儆诤瘮?shù)作用域吗蚌,在函數(shù)執(zhí)行后作用域就會被清理潦刃、內(nèi)存也隨之回收,但是由于閉包是建立在一個函數(shù)內(nèi)部的子函數(shù)胧洒,由于其可訪問上級作用域的原因,即使上級函數(shù)執(zhí)行完列赎,作用域也不會隨之銷毀,這時的子函數(shù)——也就是閉包,便擁有了訪問上級作用域中的變量的權(quán)限嚷狞,即使上級函數(shù)執(zhí)行完后作用域內(nèi)的值也不會被銷毀。
//這里就有閉包逃片,local 變量和 bar 函數(shù)就組成了一個閉包(Closure)。
function foo(){
var local = 1
function bar(){
local++
return local
}
return bar //只是為了 bar 能被使用损离,也跟閉包無關(guān),把 return bar 改成 window.bar = bar 也是一樣的,只要讓外面可以訪問到這個 bar 函數(shù)就行了
}
var func = foo()
func()
- 閉包的作用:
在本質(zhì)上,閉包就是將函數(shù)內(nèi)部和函數(shù)外部連接起來的一座橋梁秉氧,由于閉包可以緩存上級作用域,那么就使得函數(shù)外部打破了“函數(shù)作用域”的束縛攘滩,可以訪問函數(shù)內(nèi)部的變量。以平時使用的Ajax成功回調(diào)為例级解,這里其實就是個閉包,由于上述的特性芒划,回調(diào)就擁有了整個上級作用域的訪問和操作能力泵殴,提高了極大的便利。開發(fā)者不用去寫鉤子函數(shù)來操作上級函數(shù)作用域內(nèi)部的變量了吆你。閉包隨處可見,一個Ajax請求的成功回調(diào)者祖,一個事件綁定的回調(diào)方法杖虾,一個setTimeout的延時回調(diào),或者一個函數(shù)內(nèi)部返回另一個匿名函數(shù)嚷往,這些都是閉包。簡而言之贷祈,無論使用何種方式對函數(shù)類型的值進行傳遞谣蠢,當函數(shù)在別處被調(diào)用時都有閉包的身影。
7. 必考:什么是 JSONP,什么是 CORS戈泼,什么是跨域?
1. JSONP:
JSONP是JSON with Padding的略稱邀跃。它是一個非官方的協(xié)議,它允許在服務(wù)器集成JavaScript返回至 客戶端巨坊,通過javascript callback形式實現(xiàn)跨域訪問共啃。
-
JSONP的完整過程:
- 請求方:一個網(wǎng)站的前端(瀏覽器):創(chuàng)建一個script,src指向響應(yīng)方究珊,同時傳一個查詢參數(shù)callback=xxx;不用callbackName,而是用callback。
- 響應(yīng)方:另一個網(wǎng)站的后端(服務(wù)器),根據(jù)查詢參數(shù)callbackName,構(gòu)造形如xxx.call(undefined,'你要的參數(shù)')響應(yīng)瑟蜈。
- 瀏覽器接收到響應(yīng)就會執(zhí)行回調(diào)函數(shù)xxx.call(undefined,'你要的參數(shù)')宪躯。
- 請求方就會知道了他想要的數(shù)據(jù)(執(zhí)行函數(shù)體里面的執(zhí)行語句)掂林。
這就是JSONP
-
行業(yè)約定:
- 查詢參數(shù)要用callback來指定精置,在jQuery中用jQuery_callback。
- 回調(diào)函數(shù)名不固定,就用用隨機函數(shù)名火欧,簡單又避免函數(shù)名重復的問題,例如不叫xxx ,而是jQuery12343這種隨機數(shù)衅檀;只要符合變量名規(guī)則就行打却。
- 調(diào)用函數(shù)后馬上刪除捌肴,避免污染全局變量。
為什么SJONP只能發(fā)起不能發(fā)post請求坦喘?
因為JSONP是通過動態(tài)創(chuàng)建scriipt實現(xiàn)的,動態(tài)創(chuàng)建的script的時候只能發(fā)送get請求西设,不能發(fā)送post請求.jQuery實現(xiàn)Ajax:
$.ajax({
url : "http://jack.com:8080/pay",
dataType : "jsonp",
success : function(response){
if(response === "success"){
... //執(zhí)行語句
}
}
})
2. CORS:跨源資源分享
Cross-Origin Resource Sharing瓣铣,是W3C標準,它是解決Ajax跨源請求的根本方法贷揽,CORS 允許發(fā)送任何類型的請求
用法:
response.setHeader('Access-Control-Allow-Origin':'http://haha.com:8080')
//設(shè)置CORS,http://haha.com:8001這個網(wǎng)站可以訪問本服務(wù)器響應(yīng)內(nèi)容
后臺用 JSONP 還是 CORS? 首先JSONP 不能發(fā)起POST請求但可以實現(xiàn)跨源請求棠笑。CORS可以發(fā)起多種類型的請求(后臺必須要用POST請求的話只能用CORS),但是需要訪問的話在后臺設(shè)置CORS才能實現(xiàn)跨源請求丐一。
3. 跨域:
跨域是指從一個域名的網(wǎng)頁去請求另一個域名的資源。比如從http://www.baidu.com/ 頁面去請求 http://www.google.com 的資源√局蓿跨域的嚴格一點的定義是:只要 協(xié)議,域名坏快,端口有任何一個的不同级及,就被當作是跨域硼啤。
8. 尘觯考:async/await 怎么用葫辐,如何捕獲異常歌馍?
捕獲異常就是拋出promise.reject異常值
aysnc function fn(){
try{
var z = await.promise.reject(3)
}catch(e){
console.log(e) //3
}
}
fn();
9.常考:如何實現(xiàn)深拷貝灿里?(背代碼)
- JSON來實現(xiàn)深拷貝:
var a = {...} var b = JSON.parse( JSON.stringify(a) )
缺點:JSON 不支持函數(shù)撵儿、引用掸哑、undefined江锨、RegExp、Date……
- 遞歸:
function clone(object){
var object2
if(! (object instanceof Object) ){
return object
}else if(object instanceof Array){
object2 = []
}else if(object instanceof Function){
object2 = eval(object.toString())
}else if(object instanceof Object){
object2 = {}
}
//你也可以把 Array Function Object 都當做 Object 來看待烟号,參考 https://juejin.im/post/587dab348d6d810058d87a0a
for(let key in object){
object2[key] = clone(object[key])
}
return object2
}
判斷類型:
檢查循環(huán)引用(環(huán)):
10. 骋乩辏考:如何用正則實現(xiàn) trim()雹食?
function trim(string){
return string.replace(/^\s | \s+$/g,' ')
}
11. 考:不用 class 如何實現(xiàn)繼承?用 class 又如何實現(xiàn)门扇?
- 不用class實現(xiàn)繼承:原型鏈
function Animal(){ this.body = '肉體' } Animal.prototype.move = function(){ } function Human(name){ Animal.apply(this, arguments) this.name = name } // Human.prototype.__proto__ = Animal.prototype // 非法 var f = function(){} f.prototype = Animal.prototype Human.prototype = new f() Human.prototype.useTools = function(){} var qinglin = new Human()
- 使用class 實現(xiàn)繼承:
class Animal{
constructor(){
this.body = '肉體'
},
move(){}
}
class Dog extends Animal{
constructor(name){
super(name)
this.name = name
},
useTools(){}
}
var qinglin = new Human()
12. 辰抵考:如何實現(xiàn)數(shù)組去重带到?
- 第一種方案:
//計數(shù)排序的邏輯(只能正整數(shù))
var a = [4,2,5,6,3,4,5]
var hashTab = {}
for(let i=0; i<a.length;i++){
if(a[i] in hashTab){
// 什么也不做
}else{
hashTab[ a[i] ] = true
}
}
//hashTab: {4: true, 2: true, 5: true, 6:true, 3: true}
console.log(Object.keys(hashTab)) // ['4','2','5','6','3']
- 第二種方案:
function unique(array){
return [...new set(array)]
}
13. 棄:== 相關(guān)題目(反著答)
14. 送命題:手寫一個 Promise
function Promise(executor) {
let self = this;
self.status = 'pending'; //等待態(tài)
self.value = undefined; //成功的返回值
self.reason = undefined; //失敗的原因
function resolve(value){
if(self.status === 'pending'){
self.status = 'resolved';
self.value = value;
}
}
function reject(reason) {
if(self.status === 'pending') {
self.status = 'rejected';
self.reason = reason;
}
}
try{
executor(resolve, reject);
}catch(e){
reject(e);// 捕獲時發(fā)生異常鸳碧,就直接失敗
}
}
//onFufiled 成功的回調(diào)
//onRejected 失敗的回調(diào)
Promise.prototype.then = function (onFufiled, onRejected) {
let self = this;
if(self.status === 'resolved'){
onFufiled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
}
module.exports = Promise;
4. Dom
1. 考:事件委托
//錯誤版(但是可能能過)bug 在于,如果用戶點擊的是 li 里面的 span,就沒法觸發(fā) fn愤兵,這顯然不對。
ul.addEventListener('click',function(e){
if(e.target.tagName.tiLowerCase === 'li'){
console.log('li被點擊了')
fn() //執(zhí)行謀個函數(shù)
}
})
最標準版:
function delegate(element, eventType, selector, fn) {
element.addEventListener(eventType, e => {
let el = e.target
while (!el.matches(selector)) {
if (element === el) {
el = null
break
}
el = el.parentNode
}
el && fn.call(el, e, el)
})
return element
}
2. 曾考:用 mouse 事件寫一個可拖曳的 div
//html
<div id="xxx"></div>
//js
var dragging = false
var position = null
xxx.addEventListener('mousedown',function(e){
dragging = true
position = [e.clientX, e.clientY]
})
document.addEventListener('mousemove', function(e){
if(dragging === false){return}
console.log('hi')
const x = e.clientX
const y = e.clientY
const deltaX = x - position[0]
const deltaY = y - position[1]
const left = parseInt(xxx.style.left || 0)
const top = parseInt(xxx.style.top || 0)
xxx.style.left = left + deltaX + 'px'
xxx.style.top = top + deltaY + 'px'
position = [x, y]
})
document.addEventListener('mouseup', function(e){
dragging = false
})
5. HTTP
1. 考:HTTP 狀態(tài)碼知道哪些扣泊?分別什么意思近范?
狀態(tài)碼 202 表示:服務(wù)器已接受請求,但尚未處理延蟹。
狀態(tài)碼 204 表示:請求處理成功评矩,但沒有資源可返回。
狀態(tài)碼 206 表示:服務(wù)器已經(jīng)成功處理了部分 GET 請求阱飘。
狀態(tài)碼 301 表示:請求的資源已被永久的分配了新的 URI斥杜。
狀態(tài)碼 302 表示:請求的資源臨時的分配了新的 URI。
狀態(tài)碼 400 表示:請求報文中存在語法錯誤沥匈。
狀態(tài)碼 401 表示:發(fā)送的請求需要有通過 HTTP 認證的認證信息蔗喂。
狀態(tài)碼 403 表示:對請求資源的訪問被服務(wù)器拒絕了。
狀態(tài)碼 404 表示:服務(wù)器上無法找到請求的資源高帖。
狀態(tài)碼 500 表示:服務(wù)器端在執(zhí)行請求時發(fā)生了錯誤缰儿。
狀態(tài)碼 503 表示:服務(wù)器暫時處于超負債或正在進行停機維護,現(xiàn)在無法處理請求散址。
2. 大公司必考:HTTP 緩存有哪幾種乖阵?
- 幾種緩存:
Etag —— 是根據(jù)瀏覽器和服務(wù)器資源的唯一特征標識符(比如MD5)宣赔,果服務(wù)器發(fā)現(xiàn)ETag匹配不上,那么直接以常規(guī)GET 200回包形式將新的資源(當然也包括了新的ETag)發(fā)給客戶端瞪浸;如果ETag是一致的儒将,則直接返回304知會客戶端直接使用本地緩存即可。
Expires —— 自然也需要有個東西來啟用緩存和定義緩存時間默终,對http1.0而言椅棺,Expires就是做這件事的首部字段。 Expires的值對應(yīng)一個GMT(格林尼治時間)齐蔽,指定的是過期時間點(相對于服務(wù)器時間而言)两疚,來決定是否重新發(fā)起請求。這個方法會有bug含滴,但是如果用戶的本地時間錯亂了诱渤,可能會有問題
Cache-Control —— 設(shè)置一個時間段,它意味著該資源是從原服務(wù)器上取得的谈况,且其緩存(新鮮度)的有效時間為一段時間勺美,在后續(xù)這段時間內(nèi),用戶重新訪問該資源則無須發(fā)送請求碑韵。 當然這種組合的方式也會有些限制赡茸,比如 no-cache 就不能和 max-age、min-fresh祝闻、max-stale 一起搭配使用占卧。 - 之間區(qū)別:
- Expire和Cache-Control之間區(qū)別:前者是指定過期時間點,而后者是指定有效緩存的時間段联喘。
- Etag 和 Cache-Control之間的區(qū)別:Cache-Control的讀取時從瀏覽器本地文件中讀取的(無請求)华蜒,而Etag是有請求的。
- 近幾年有些大公司使用 PWA來緩存:那么瀏覽器的http緩存順序是什么豁遭?
3. 考:GET 和 POST 的區(qū)別
-
錯誤答案:
- POST安全叭喜,GET不安全,
- Get 有長度限制(URL 長度有1024字節(jié))蓖谢,而Post沒有長度限制(一般URL的長度限制在4M)捂蕴,
- Get的參數(shù)是放在URL上,Post的參數(shù)放在消息體里面蜈抓,
- Get只需要一個報文启绰,Post需要兩個以上。
- Get是冪等的沟使,Post不冪等委可。
正確答案: Get是獲取數(shù)據(jù),Post是提交數(shù)據(jù)。其他的沒有本質(zhì)的區(qū)別着倾。
4. ookie V.S. LocalStorage V.S. SessionStorage V.S. Session
- Cookie —— http協(xié)議的一部分
- session —— 存在服務(wù)器中的一小段哈希表(每個用戶都有自己的sessionId請求時存放在session中拾酝,),是服務(wù)器與瀏覽器之間的一段時間內(nèi)的會話卡者。
- LocalStorage —— html5提供的API ,常用屬性有 setItem()/getItem()/LocalStorage.clear()/removeItem().實現(xiàn)了不同頁面中保存變量且其值不變蒿囤。讓后端有了記憶力。
- Cookie 與 session之間的關(guān)系:
a. Cookie 存在瀏覽器的文件里崇决,Session 存在服務(wù)器的文件里
b.Session 是基于 Cookie 實現(xiàn)的材诽,具體做法就是把 SessionID 存在 Cookie 里 - Cookie 與 LocalStorage之間的關(guān)系:
a. Cookie大小約4kb,LocalStorage一般有5M,
b. Cookie 會被發(fā)送到服務(wù)器,LocalStorage不會
c.Cookie 會存儲用戶信息恒傻,LocalStorage存儲沒用的東西脸侥。 - SessionStorage 與 LocalStorage之間的關(guān)系:
a.LocalStorage 一般不會自動過期(除非用戶手動清除),而 SessionStorage 在session(會話)結(jié)束時過期(如關(guān)閉瀏覽器).
5. HTTP1和 HTTP2的區(qū)別:
HTTP2的新特性:
a. 多路復用 (MultiPlexing) —— 解決了線頭阻塞的問題盈厘,減少了 TCP 連接數(shù)量和 TCP 連接慢啟動造成的問題
b. 服務(wù)端推送 (Server Push) —— 瀏覽器發(fā)送一個請求睁枕,服務(wù)器主動向瀏覽器推送與這個請求相關(guān)的資源,這樣瀏覽器就不用發(fā)起后續(xù)請求沸手。
c. Header 壓縮 (HPACK) —— 使用 HPACK 算法來壓縮首部內(nèi)容
d. 二進制分幀層 (Binary Framing Layer)—— 幀是數(shù)據(jù)傳輸?shù)淖钚挝煌庥觯远M制傳輸代替原本的明文傳輸,原本的報文消息被劃分為更小的數(shù)據(jù)幀契吉。
6. 框架
6.1 Vue
1. 必考:watch 和 computed 和 methods 區(qū)別是什么跳仿?
watch是監(jiān)聽數(shù)據(jù),computed是計算屬性捐晶;
watch和computed的最大區(qū)別是:computed是有緩存的塔嬉,如果computed依賴的屬性沒有變化,computed屬性就不會重新激計算租悄。而watch則是看到一次計算一次。
2. 必考:Vue 有哪些生命周期鉤子函數(shù)恩袱?分別有什么用泣棋?
Vue的生命周期:
- beforeCreate : 實例初始化之后,數(shù)據(jù)觀測(data observoe)和事件配置(event/watcher)調(diào)用之前調(diào)用畔塔。
- created : 實例初始化之后潭辈,數(shù)據(jù)觀測和事件配置調(diào)用之前調(diào)用。
- beforeMount : 掛載組件開始之前被調(diào)用澈吨,相關(guān)的render函數(shù)首次被調(diào)用
- Mounted : el 被創(chuàng)建的vm.$el 替換把敢,被掛載到實例上之后調(diào)用該鉤子,
- beforeUpdate : 數(shù)據(jù)更新時谅辣,發(fā)生在虛擬DOM 打補丁之前修赞。
- update : 由于數(shù)據(jù)更新導致的虛擬DOM重新渲染和打補丁之后會調(diào)用。
- beforeDestroy :實例被銷毀之前,這個時候?qū)嵗匀煌耆捎谩?/li>
- destroyed : 實例銷毀之后調(diào)用柏副,調(diào)用后Vue 實例指示的所有東西都會被解除綁定勾邦,所有事件監(jiān)聽都會被移除,所有 的子實例也會被銷毀割择。
Vue 的 Mounted生命周期進行數(shù)據(jù)請求眷篇。
3. 考:Vue 如何實現(xiàn)組件間通信?
- 父子組件: $emit('xxx',data) on('xxx',function(){})
- 爺孫組件之間: 兩次 v-on 通過爺爺 => 爸爸 => 孫子
- 任意組件之間通信:eventBus = new Vue() 來通信荔泳;主要API: eventBus.
emit ; 任意組件之間也可以使用 Vuex來通信蕉饼。
- Vuex是專門為Vue應(yīng)用程序開發(fā)的狀態(tài)管理工具。Vuex的核心概念有以下幾種:
state => 基本數(shù)據(jù)
getters => 從基本數(shù)據(jù)派生的數(shù)據(jù)
mutations => 提交更改數(shù)據(jù)的方法玛歌,同步昧港!
actions => 像一個裝飾器,包裹mutations沾鳄,使之可以異步慨飘。
modules => 模塊化Vuex
4. 必考:Vue 數(shù)據(jù)響應(yīng)式怎么做到的?(以前的概念:雙向綁定)
v-model實現(xiàn)響應(yīng)式:一句話總結(jié)就是:在數(shù)據(jù)渲染時使用prop渲染數(shù)據(jù)译荞,將prop綁定到子組件自身的數(shù)據(jù)上瓤的,修改數(shù)據(jù)時更新自身數(shù)據(jù)來替代prop,watch子組件自身數(shù)據(jù)的改變吞歼,觸發(fā)事件通知父組件更改綁定到prop的數(shù)據(jù)圈膏。
a. Object.defineProperty 通過 getter 和 setter 劫持了對象賦值的過程,在這個過程中可以進行更新 dom 操作等等篙骡。
b. Vue 不能檢測到對象屬性的添加或刪除稽坤,解決方法是手動調(diào)用 Vue.set 或者 this.$set.
const component = {
model : {
prop : 'value',
event : 'change'
},
props : ['value'],
template:`
<div>
<component v-model="value"></component>
</div>
`,
methods : {
handleInput(e){
this.$emit('change',e.target.value)
}
}
}
5. 必考:Vue.set 是做什么用的?
Vue不能識別添加或刪除屬性的變化糯俗,vue不能在已經(jīng)創(chuàng)建的實力上動態(tài)的添加新的根級響應(yīng)式屬性尿褪,而是必須用 Vue.set方法將響應(yīng)式屬性添加到嵌套對象上。
6. Vuex 你怎么用的得湘?
Vuex是Vue.js應(yīng)用的程序的狀態(tài)管理工具杖玲。
其核心概念有以下:
state : 基本數(shù)據(jù)
getters : 基本數(shù)據(jù)派生的數(shù)據(jù)
mutations : 提交更改數(shù)據(jù)的方法,同步
actions : 相當于裝飾器淘正,封裝mutations,使之可以異步實現(xiàn)
mudules : 模塊化Vuex;
7. VueRouter 你怎么用的摆马?
VueRouter是Vue.js官方的路由器管理。澈柽海考點:重定向模式囤采,history模式,導航守衛(wèi)惩淳,路由懶加載(import('./Foo.vue')//組件路徑,返回promise對象)蕉毯。
1. 重定向模式:“重定向”的意思是,當用戶訪問 /a時,URL 將會被替換成 /b恕刘,然后匹配路由為 /b缤谎。
2. 導航守衛(wèi):導航守衛(wèi)是路由跳轉(zhuǎn)過程中的一些鉤子函數(shù),路由跳轉(zhuǎn)是一個大的過程褐着,這個大的過程分為跳轉(zhuǎn)前中后等多個細節(jié)過程坷澡,在每一個過程中都有一個函數(shù),這些個函數(shù)能讓你操作一些其他的操作的機會含蓉,這就是導航守衛(wèi)频敛。
導航守衛(wèi)有三種模式:
* 全局的:指路由在實例上直接操作的函數(shù):鉤子函數(shù)按執(zhí)行順序包括beforeEach、beforeResolve馅扣、afterEach三個斟赚。
* 單個路由獨享的:指單個路由配置的時候可以設(shè)置的函數(shù),只有一個函數(shù):beforeEnter差油,其參數(shù)有to,from,next.
* 組件內(nèi)的:組件內(nèi)執(zhí)行的鉤子函數(shù)拗军,類似于組件內(nèi)的生命周期,鉤子函數(shù)按執(zhí)行順序包括beforeRouteEnter蓄喇、beforeRouteUpdate发侵、beforeRouteLeave三個。
3. history模式:history模式采用html5的新特性妆偏,提供了兩個新方法刃鳄,pushState ,replaceState,可以對瀏覽器歷史記錄棧進行修改,以及popState事件的監(jiān)聽到狀態(tài)變更钱骂。
4. 路由懶加載:當打包構(gòu)建應(yīng)用時叔锐,JavaScript 包會變得非常大,影響頁面加載见秽。如果我們能把不同路由對應(yīng)的組件分割成不同的代碼塊愉烙,然后當路由被訪問的時候才加載對應(yīng)組件,這樣就更加高效了解取。
結(jié)合 Vue 的異步組件和 Webpack 的[代碼分割功能]齿梁,輕松實現(xiàn)路由組件的懶加載。
使用方法:
import('./Foo.vue') // 返回 Promise肮蛹。
const router = new VueRouter({
routes: [
{
path: '/Foo',
name: 'Home',
component:() = import('../views/home')
}
]
})
8. 路由守衛(wèi)是什么创南?(導航守衛(wèi)的鉤子函數(shù)來完成)
- 業(yè)務(wù):
- 監(jiān)聽整個項目的路由變化情況 全局的前置守衛(wèi)
- 監(jiān)聽某個路由的變化情況 路由的獨享守衛(wèi)
- 監(jiān)聽的路由組件的路由變化情況 組件內(nèi)的導航守衛(wèi)
- 業(yè)務(wù):
6.2 React
1. 必考:受控組件 V.S. 非受控組件
舉個例子:
<FInput value={x} onChange={fn} /> //受控組件
<FInput defaultValue={x} />//非受控組件
2. 必考:React 有哪些生命周期函數(shù)伦忠?分別有什么用?(Ajax 請求放在哪個階段稿辙?)
- 生命周期函數(shù):
一昆码、初始化階段:
getDefaultProps:獲取實例的默認屬性
getInitialState:獲取每個實例的初始化狀態(tài)
constructor :聲明State變量
componentWillMount:組件即將被裝載、渲染到頁面上
render:組件在這里生成虛擬的DOM節(jié)點
componentDidMount:組件真正在被裝載之后
二、運行中狀態(tài):
componentWillReceiveProps:組件將要接收到屬性的時候調(diào)用
shouldComponentUpdate:組件接受到新屬性或者新狀態(tài)的時候(可以返回false赋咽,接收數(shù)據(jù)后不更新旧噪,阻止
render調(diào)用,后面的函數(shù)不會被繼續(xù)執(zhí)行了)
componentWillUpdate:組件即將更新不能修改屬性和狀態(tài)render:組件重新描繪
componentDidUpdate:組件已經(jīng)更新三
銷毀階段:
componentWillUnmount:組件即將銷毀 - 異步請求:ajax異步請求數(shù)據(jù)應(yīng)該放在 componentDidMount函數(shù)中脓匿。
3. 必考:React 如何實現(xiàn)組件間通信淘钟?
- 父組件向子組件通訊: 父組件可以向子組件通過傳 props 的方式,向子組件進行通訊
- 子組件向父組件通訊: props+回調(diào)的方式,父組件向子組件傳遞props進行通訊陪毡,此props為作用域為父組件自身的函數(shù)米母,子組件調(diào)用該函數(shù),將子組件想要傳遞的信息毡琉,作為參數(shù)铁瞒,傳遞到父組件的作用域中
- 兄弟組件通信: 找到這兩個兄弟節(jié)點共同的父節(jié)點,結(jié)合上面兩種方式由父節(jié)點轉(zhuǎn)發(fā)信息進行通信
- 跨層級通信: Context設(shè)計目的是為了共享那些對于一個組件樹而言是“全局”的數(shù)據(jù),例如當前認證的用戶桅滋、主題或首選語言,對于跨越多層的全局數(shù)據(jù)通過Context通信再適合不過
- 發(fā)布訂閱模式: 發(fā)布者發(fā)布事件慧耍,訂閱者監(jiān)聽事件并做出反應(yīng),我們可以通過引入event模塊進行通信
- 全局狀態(tài)管理工具: 借助Redux或者Mobx等全局狀態(tài)管理工具進行通信,這種工具會維護一個全局狀態(tài)中心Store,并根據(jù)不同的事件產(chǎn)生新的狀態(tài)
4. 必考:shouldComponentUpdate 有什么用?
shouldComponentUpdate 這個方法用來判斷是否需要調(diào)用 render 方法重新描繪 dom丐谋。因為 dom 的描繪非常消耗性能芍碧,如果我們能在 shouldComponentUpdate 方法中能夠?qū)懗龈鼉?yōu)化的 dom diff 算法,可以極大的提高性能笋鄙。
5. 考:虛擬 DOM 是什么师枣?
react操作中render的結(jié)果并不能得到一個真正的DOM節(jié)點,而是一個輕量級的javascript對象,我們稱之為虛擬DOM萧落。
就是用來模擬DOM的一個對象践美,有一些常用屬性,并且更新 UI 主要就是通過對比(DIFF)舊的虛擬 DOM 樹 和新的虛擬 DOM 樹的區(qū)別完成的找岖,對真實的DOM進行最小化的修改陨倡。
- 優(yōu)點:虛擬DOM具有批處理和高效的Diff算法,最終表現(xiàn)在DOM上的修改只是變更的部分,可以保證非常高效的渲染,優(yōu)化性能.
- 缺點:首次渲染大量DOM時许布,由于多了一層虛擬DOM的計算兴革,會比innerHTML插入慢
6. 必考:什么是高階組件?
高階組件是一個以組件為參數(shù)并返回一個新組件的函數(shù)蜜唾。HOC 運行你重用代碼杂曲、邏輯和引導抽象。最常見的高階組件是 Redux 的 connect 函數(shù)袁余。比如 connect(mapState)(MyComponent) 接受組件 MyComponent擎勘,返回一個具有狀態(tài)的新 MyComponent 組件。除了簡單分享工具庫和簡單的組合颖榜,HOC 最好的方式是共享 React 組件之間的行為棚饵。如果你發(fā)現(xiàn)你在不同的地方寫了大量代碼來做同一件事時煤裙,就應(yīng)該考慮將代碼重構(gòu)為可重用的 HOC。
- 高階組件是一個以組件為參數(shù)并返回一個新組件的函數(shù)噪漾。
- 如果你發(fā)現(xiàn)你在不同的地方寫了大量代碼來做同一件事時硼砰,就應(yīng)該考慮將代碼重構(gòu)為可重用的 HOC。
7. React diff 的原理是什么欣硼?
對比兩顆DOM樹的區(qū)別题翰,找出其中不同的部分。React diff 作為Virtual DOM的加速器分别,其算法上的改進優(yōu)化是 React 整個界面渲染的基礎(chǔ)遍愿,以及性能提高的保障,同時也是 React 源碼中最神秘耘斩、最不可思議的部分沼填,本文將剖析 React diff 的不可思議之處。
8. 考 Redux 是什么括授?
Redux是一個庫坞笙,它是javascript狀態(tài)容器(事件分發(fā)中心),提供可以預(yù)策劃的狀態(tài)管理荚虚。核心概念的名詞:action reducer store 單向數(shù)據(jù)流薛夜。
常用的API 有:store.dispatch(action) store.getState() 等。
9. connect 的原理是什么版述?
是react-redux庫提供的API梯澜,是基于react和redux封裝的函數(shù),負責連接React和Redux渴析,把組件和store連接起來組成一個新的組件晚伙。
* 獲取state: connect通過context獲取Provider中的store,通過store.getState()獲取整個store tree 上所有state
- 包裝原組件: 將state和action通過props的方式傳入到原組件內(nèi)部wrapWithConnect返回一個ReactComponent對象Connect俭茧,Connect重新render外部傳入的原組件WrappedComponent咆疗,并把connect中傳入的mapStateToProps, mapDispatchToProps與組件上原有的props合并后,通過屬性的方式傳給WrappedComponent
- 監(jiān)聽store tree變化: connect緩存了store tree中state的狀態(tài),通過當前state狀態(tài)和變更前state狀態(tài)進行比較,從而確定是否調(diào)用this.setState()方法觸發(fā)Connect及其子組件的重新渲染
10. (組件的)狀態(tài)(state)和屬性(props)之間有何不同母债?
- State 是一種數(shù)據(jù)結(jié)構(gòu)午磁,用于組件掛載時所需數(shù)據(jù)的默認值。State 可能會隨著時間的推移而發(fā)生突變毡们,但多數(shù)時候是作為用戶事件行為的結(jié)果迅皇。
- Props(properties 的簡寫)則是組件的配置。props 由父組件傳遞給子組件衙熔,并且就子組件而言喧半,props 是不可變的(immutable)。組件不能改變自身的 props青责,但是可以把其子組件的 props 放在一起(統(tǒng)一管理)挺据。Props 也不僅僅是數(shù)據(jù)--回調(diào)函數(shù)也可以通過 props 傳遞。
7. TypeScript
1. never 類型是什么脖隶?
never是不應(yīng)該出現(xiàn)的類型扁耐,never類型可以理解為沒有返回指的函數(shù)或者總是會拋出錯誤的函數(shù)。
//舉例:
function(){while return{}}//如果函數(shù)內(nèi)含有 while(true) {}
function foo(){
throw new Error('not implemented')
}
//foo的返回類型是never
【注意】never僅能被賦值給另一個never
viod表示沒有任何類型产阱。never表示永遠不存在的類型婉称。
2. TypeScript 比起 JavaScript 有什么優(yōu)點?
目前主流框架都已經(jīng)使用了typescript,Vue3.0\React都已經(jīng)使用了构蹬,typescript是javascript的超集王暗,也就是說js能做到的東西typescript都能做到,javascript程序員會的東西typescript程序員都會庄敛,js程序員不會的他們也都會俗壹,所以typescript一定是以后的主流。其優(yōu)點:typescript提供了類型約束藻烤,因此可控绷雏,更容易重構(gòu),做更大的項目怖亭,更容易維護涎显。
- bug 顯著減少,之前會遇到的 xxx 為空的問題幾乎不會出現(xiàn)了兴猩,類型相關(guān) bug 直線減少期吓。
- 應(yīng)用更可控,當你需要約束某些代碼的時候倾芝,用類型就能很簡單地做到讨勤,比如 React 里強制寫 displayName 方便調(diào)試。
- 查文檔更方便蛀醉,以前要打開瀏覽器看文檔悬襟,現(xiàn)在直接查看定義就基本明白了。
項目目前只支持 JS拯刁,也沒有關(guān)系脊岳,只需要加一個 ts-loader 或者 awesome-typescript-loader 就能提供 TypeScript 支持,TS 可以和 JS 共存垛玻。學完 JS 后割捅,只需要學習一下類型聲明就可以掌握 TS 了。TS 就是在 JS 上加上類型聲明帚桩,這樣我們就能知道代碼是否「大概」正確亿驾。
另外,這種方式速度非痴撕浚快莫瞬,快到你只要修改代碼儡蔓,TS 就能告訴你代碼是否「大概」正確。
從而避免很多 bug疼邀。
8. Webpack
參考鏈接【https://zhuanlan.zhihu.com/p/44438844】
1. 必考:有哪些常見 loader 和 plugin喂江,你用過哪些?
三者都是前端構(gòu)建工具旁振,grunt和gulp在早期比較流行获询,現(xiàn)在webpack相對來說比較主流,webpack會自動地遞歸解析入口所需要加載的所有資源文件拐袜,然后用不同的Loader來處理不同的文件吉嚣,用Plugin來擴展webpack功能。
常見的loader—— 加載器
* html —— pug-loader markdown-loader
* css —— style-loader less-loader scss-loader postloader
* js —— babel-loader
* 圖片 —— url-loader eslint-loader
- file-loader:把文件輸出到一個文件夾中蹬铺,在代碼中通過相對 URL 去引用輸出的文件
- url-loader:和 file-loader 類似尝哆,但是能在文件很小的情況下以 base64 的方式把文件內(nèi)容注入到代碼中去
- source-map-loader:加載額外的 Source Map 文件,以方便斷點調(diào)試
- image-loader:加載并且壓縮圖片文件
- babel-loader:把 ES6 轉(zhuǎn)換成 ES5
- css-loader:加載 CSS丛塌,支持模塊化较解、壓縮、文件導入等特性
- style-loader:把 CSS 代碼注入到 JavaScript 中赴邻,通過 DOM 操作去加載 CSS印衔。
- eslint-loader:通過 ESLint 檢查 JavaScript 代碼
常見的plugin—— 用Plugin來擴展webpack功能
- html —— html-webpack-plugin
- css —— ex tract-text-plugin
- js ——
- define-plugin:定義環(huán)境變量
- commons-chunk-plugin:提取公共代碼
- uglifyjs-webpack-plugin:通過UglifyES壓縮ES6代碼
2. loader 和 plugin的區(qū)別是什么?
- 不同的作用:
a. Loader直譯為"加載器"姥敛。Webpack將一切文件視為模塊奸焙,但是webpack原生是只能解析js文件,如果想將其他文件也打包的話彤敛,就會用到loader与帆。 所以Loader的作用是讓webpack擁有了加載和解析非JavaScript文件的能力。
b . Plugin直譯為"插件"墨榄。Plugin可以擴展webpack的功能玄糟,讓webpack具有更多的靈活性。 在 Webpack 運行的生命周期中會廣播出許多事件袄秩,Plugin 可以監(jiān)聽這些事件阵翎,在合適的時機通過 Webpack 提供的 API 改變輸出結(jié)果。 - 不同的用法:
a. Loader在module.rules中配置之剧,也就是說他作為模塊的解析規(guī)則而存在郭卫。 類型為數(shù)組,每一項都是一個Object背稼,里面描述了對于什么類型的文件(test)贰军,使用什么加載(loader)和使用的參數(shù)(options)
b. Plugin在plugins中單獨配置。 類型為數(shù)組蟹肘,每一項是一個plugin的實例词疼,參數(shù)都通過構(gòu)造函數(shù)傳入俯树。
3. 必考:如何按需加載代碼?
Vue UI組件庫的按需加載 為了快速開發(fā)前端項目贰盗,經(jīng)常會引入現(xiàn)成的UI組件庫如ElementUI聘萨、iView等,但是他們的體積和他們所提供的功能一樣童太,是很龐大的。 而通常情況下胸完,我們僅僅需要少量的幾個組件就足夠了书释,但是我們卻將龐大的組件庫打包到我們的源碼中,造成了不必要的開銷赊窥。
不過很多組件庫已經(jīng)提供了現(xiàn)成的解決方案爆惧,如Element出品的[babel-plugin-component](https://link.zhihu.com/?target=https%3A//github.com/ElementUI/babel-plugin-component)
和AntDesign出品的[babel-plugin-import](https://link.zhihu.com/?target=https%3A//github.com/ant-design/babel-plugin-import)
安裝以上插件后,在.babelrc
配置中或babel-loader
的參數(shù)中進行設(shè)置锨能,即可實現(xiàn)組件按需加載了伤为。
{
"presets": [["es2015", { "modules": false }]],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
單頁應(yīng)用的按需加載 現(xiàn)在很多前端項目都是通過單頁應(yīng)用的方式開發(fā)的丰刊,但是隨著業(yè)務(wù)的不斷擴展,會面臨一個嚴峻的問題——首次加載的代碼量會越來越多,影響用戶的體驗僚祷。
通過import(*)
語句來控制加載時機,webpack內(nèi)置了對于import(*)
的解析佳遣,會將import(*)
中引入的模塊作為一個新的入口在生成一個chunk奸鸯。 當代碼執(zhí)行到import(*)
語句時,會去加載Chunk對應(yīng)生成的文件浸剩。import()
會返回一個Promise對象钾军,所以為了讓瀏覽器支持,需要事先注入Promise polyfill
4. 必考:如何提高構(gòu)建速度绢要?
- 多入口情況下吏恭,使用CommonsChunkPlugin來提取公共代碼
- 通過externals配置來提取常用庫
- 利用DllPlugin和DllReferencePlugin預(yù)編譯資源模塊 通過DllPlugin來對那些我們引用但是絕對不會修改的npm包來進行
- 預(yù)編譯,再通過DllReferencePlugin將預(yù)編譯的模塊加載進來重罪。
- 使用Happypack 實現(xiàn)多線程加速編譯(多核CPU進行打包)
- 使用webpack-uglify-parallel來提升uglifyPlugin的壓縮速度樱哼。 原理上webpack-uglify-parallel采用了多核并行壓縮來提升壓縮速度
- 使用Tree-shaking和Scope Hoisting來剔除多余代碼(Tree-Shaking不要說,說了會追問)
5. 義出的文件過大怎么辦蛆封?
- commonsChunkPlugin: 提取通用模塊(最新的webpack已經(jīng)不使用了這個插件)
- 壓縮 js,css,圖片
- 使用動態(tài)加載:import()
9. 網(wǎng)絡(luò)安全
1. 考:什么是 XSS唇礁?如何預(yù)防?
XSS —— Cross-Site Scripting 跨站腳本惨篱。
用戶 A 提交評論「小谷你好」到服務(wù)器盏筐,然后用戶 B 來訪問網(wǎng)站,看到了 A 的評論「小谷你好」砸讳,這里沒有 XSS琢融。
惡意用戶 H 提交評論「<script>console.log(document.cookie)</script>」界牡,然后用戶 B 來訪問網(wǎng)站,這段腳本在 B 的瀏覽器直接執(zhí)行漾抬,惡意用戶 H 的腳本就可以任意操作 B 的 cookie宿亡,而 B 對此毫無察覺。有了 cookie纳令,惡意用戶 H 就可以偽造 B 的登錄信息挽荠,隨意訪問 B 的隱私了。而 B 始終被蒙在鼓里平绩。
防范方法:
- 后臺模板問題
<p>
評論內(nèi)容:<?php echo $content; ?>
</p>
$content 的內(nèi)容圈匆,沒有經(jīng)過任何過濾,原樣輸出捏雌。
要解決這個原因跃赚,只需要后臺輸出的時候,將可疑的符號 < 符號變成 < (HTML實體)就行性湿。
- 前端代碼問題
$p.html(content)
或者
$p = $('<p>'+ content +'</p>')
content 內(nèi)容又被原樣輸出了纬傲。解決辦法就是不要自己拼 HTML,盡量使用 text 方法肤频。如果一定要使用 HTML叹括,就把可疑符號變成 HTML 實體。
2. 必考:什么是 CSRF着裹?如何預(yù)防领猾?
Cross Site Request Forgery,跨站請求偽造。其原理是攻擊者構(gòu)造網(wǎng)站后臺某個功能接口的請求地址骇扇,誘導用戶去點擊或者用特殊方法讓該請求地址自動加載摔竿。用戶在登錄狀態(tài)下這個請求被服務(wù)端接收后會被誤以為是用戶合法的操作。對于 GET 形式的接口地址可輕易被攻擊少孝,對于 POST 形式的接口地址也不是百分百安全继低,攻擊者可誘導用戶進入帶 Form 表單可用POST方式提交參數(shù)的頁面。
10. 開放題目
1. 必考:你遇到最難的問題是怎樣的稍走?
2. 你在團隊的突出貢獻是什么袁翁?
3. 最近在關(guān)注什么新技術(shù)
阮一峰的課本,(微博)婿脸。
4. 有沒有看什么源碼粱胜,看了后有什么記憶深刻的地方,有什么收獲
看一些源代碼狐树,命名規(guī)范的重要性焙压,從而提高代碼的可讀性。
設(shè)計模式,輪播思路涯曲。
11. 個性化題目
1. PWA
2. echarts.js / d3.js
3. three.js
4. flutter
5. SSR
12. 算法 + 數(shù)據(jù)庫
13. git 版本控制:
1. github創(chuàng)建倉庫:
命令行:
git init
git commit -m "first commit"
git add --all
創(chuàng)建遠程倉庫(復制即可)
git push -u origin master
2. 查看版本:
git log (--prety=online //輸出信息太多時可以用) //顯示最近到最遠的提交日志
git checkout -b <new-branch-name> //如果版本次數(shù)太多可以寫成 HEAD~100
//和上一步git checkout 一樣功能的命令行有 :
gitk //功能和git checkout -b <new-branch-name>一樣野哭,一圖形化工具顯示顯示已提交版本
- 注意:
git log 很很多選項:
選項 說明
-p 按補丁格式顯示每個更新之間的差異
--word-diff 按 word diff 格式顯示差異
--stat 顯示每次更新的文件修改統(tǒng)計信息
--shortstat 只顯示 --stat 中最后的行數(shù)修改添加移除統(tǒng)計
--name-only 僅在提交信息后顯示已修改的文件清單
--name-status 顯示新增、修改幻件、刪除的文件清單
--abbrev-commit 僅顯示 SHA-1 的前幾個字符拨黔,而非所有的 40 個字符
--relative-date 使用較短的相對時間顯示(比如,“2 weeks ago”)
--graph 顯示 ASCII 圖形表示的分支合并歷史
--pretty 使用其他格式顯示歷史提交信息可用的選項包括oneline绰沥,short篱蝇,full,fuller 和format(后跟指定格式)
--oneline `--pretty=oneline --abbrev-commit` 的簡化用法
3. 切換版本:
git reset --HEAD^ //返回第一個版本
git reflog 命令行提供了查詢commit id 的功能徽曲,查詢到的id 寫在git reset后面就會返回指定版本态兴。
14. 垃圾回收機質(zhì):
javascript有自動垃圾收集機制(GC:Garbage Collection),也就是說執(zhí)行環(huán)境會負責管理代碼執(zhí)行過程中使用的內(nèi)存,開發(fā)人員不用再過于擔心內(nèi)存使用的問題疟位,所需內(nèi)存的分配與無用內(nèi)存的回收完全實現(xiàn)了自動管理。
JS的垃圾回收機制是為了以防內(nèi)存泄漏喘垂,內(nèi)存泄漏的含義就是當已經(jīng)不需要某塊內(nèi)存時這塊內(nèi)存還存在著甜刻,垃圾回收機制就是間歇的不定期的尋找到不再使用的變量,并釋放掉它們所指向的內(nèi)存正勒。
- 垃圾回收方式:
- 標記清除:大部分瀏覽器以此方式進行垃圾回收得院,當變量進入執(zhí)行環(huán)境(函數(shù)中聲明變量)的時候,垃圾回收器將其標記為“進入環(huán)境”章贞,當變量離開環(huán)境的時候(函數(shù)執(zhí)行結(jié)束)將其標記為“離開環(huán)境”祥绞,在離開環(huán)境之后還有的變量則是需要被刪除的變量。標記方式不定鸭限,可以是某個特殊位的反轉(zhuǎn)或維護一個列表等蜕径。
垃圾收集器給內(nèi)存中的所有變量都加上標記,然后去掉環(huán)境中的變量以及被環(huán)境中的變量引用的變量的標記败京。在此之后再被加上的標記的變量即為需要回收的變量兜喻,因為環(huán)境中的變量已經(jīng)無法訪問到這些變量。 - 引用計數(shù):這種方式常常會引起內(nèi)存泄漏赡麦,低版本的IE使用這種方式朴皆。機制就是跟蹤一個值的引用次數(shù),當聲明一個變量并將一個引用類型賦值給該變量時該值引用次數(shù)加1泛粹,當這個變量指向其他一個時該值的引用次數(shù)便減一遂铡。當該值引用次數(shù)為0時就會被回收。
- 標記清除:大部分瀏覽器以此方式進行垃圾回收得院,當變量進入執(zhí)行環(huán)境(函數(shù)中聲明變量)的時候,垃圾回收器將其標記為“進入環(huán)境”章贞,當變量離開環(huán)境的時候(函數(shù)執(zhí)行結(jié)束)將其標記為“離開環(huán)境”祥绞,在離開環(huán)境之后還有的變量則是需要被刪除的變量。標記方式不定鸭限,可以是某個特殊位的反轉(zhuǎn)或維護一個列表等蜕径。