瀏覽器率触、 http
1终议、瀏覽器輸入地址回車發(fā)生了什么
2、http1.0,1.1穴张,2.0區(qū)別
3细燎、瀏覽器緩存(你們項目中用到了嗎? 具體干了些什么皂甘?)
4玻驻、工作原理
5、跨域解決
6偿枕、重繪重排
7击狮、前端安全(XSS,CSP, CSRF)如果防范
8、路由原理(哈希路由和history模式)
vue
1益老、父組件中想用子組件里面的方法彪蓬,有哪幾種方式
- 子組件可以在自己的created鉤子里面用 $emit 把this開放出去
- 在子組件上添加 ref 指令 拿到當前子組件的實例對象
- 其實在當前寫的項目中,使用了類似angualr2的依賴注入的機制捺萌,我們將所有的頁面行為操作档冬,和業(yè)務邏輯分別寫到了action.ts、helper.ts里面了桃纯,如果讓這兩個模塊用 @injectable 裝飾器注入到實例列表里面酷誓,外界就可以輕松使用該實例的任何方法了(但不能為了使用方法而故意注入,這樣做也有它的缺點)态坦、
2盐数、vue是怎樣實現(xiàn)數(shù)據(jù)更新的
- observe Object.defineProperty 數(shù)據(jù)劫持
- watcher 告訴訂閱值的地方 數(shù)據(jù)更新了
- compile 收到更新通知 更新狀態(tài)
3、vue和angualr2的數(shù)據(jù)更新機制的區(qū)別
4伞梯、虛擬dom
React
1玫氢、 生命周期
2、 setState同步還是異步谜诫?我想拿到異步后的數(shù)據(jù)怎么辦漾峡?react為什么把setstate設計成這樣?
3喻旷、虛擬dom的優(yōu)勢生逸、原理
4、diff算法在虛擬dom中如何比較的新舊樹的差異
5且预、錯誤邊界
js
1槽袄、 ["1", "2", "3"].map(parseInt)
[1,NaN,NaN]
2、冒泡锋谐、快排遍尺、深度遞歸
3、jsonp
4怀估、深層復制
let a = {
name: '劉',
age: 18,
say: function() {}
}
let b = JSON.parse(JSON.stringify(a));
b.age //18
b.age = 20;
b.age // 20
a.age //18
b // {name:"劉"狮鸭,age: 20}
- 這種方式可以實現(xiàn)深層復制,但是復制的對象有函數(shù)是不行的多搀。
- 如果對象是一個重復引用的特性的(自己的屬性里面有原對象信息歧蕉,無限的自己引用自己),也不適用
5康铭、es6新語法
6惯退、js原型 能手畫出來
7、bind从藤、call催跪、apply
8、隱式轉(zhuǎn)換
+'23' + 1 // 24
9夷野、數(shù)組降維
let a = [[1,2],[4,5],[77,88]];
[].concat.apply([], a)
a.flatMap(item => item)
10懊蒸、promise、async悯搔、await骑丸、generator生成器
11、發(fā)布訂閱模式妒貌、觀察者模式通危、單例模式
12、面向?qū)ο蟮奶攸c灌曙、以及用面向?qū)ο缶幊绦枰⒁獾狞c
13菊碟、0.1 + 0.2 !=0.3 為什么在刺?
14逆害、正則匹配三個連續(xù)的數(shù)字(常用正則)
15、 es6 Proxy
16蚣驼、怎樣區(qū)分function忍燥、 數(shù)組、 對象
17隙姿、快速生成一個 0到N的數(shù)組梅垄,然后要求在不生成新數(shù)組的情況下再打亂成隨機數(shù)組
let a = [...(new Array(n)).keys()];
let b = Array.from({length:n},(v, k) => k);
let c = (n) => Array.from({length:n}).map((v,k) => k);
// 利用sort
arr.sort((v1, v2) => {
return 0.5 - Math.random() > 0? 1: -1
})
// 隨機項調(diào)換位置
for(let i = 0; i < arr.length; i++) {
let curr = i;
let randomIndex = Math.floor(Math.random() * arr.length);
let currItem = arr[i];
arr[i] = arr[randomIndex];
arr[randomIndex] = currItem;
}
18、 廣度優(yōu)先遞歸一個二叉樹
19输玷、 查看兩個單鏈表是否有交叉(有重復值)
20队丝、 時間復雜度
21、 js對象和Map的區(qū)別
22欲鹏、 斐波那切數(shù)列 (分析下 函數(shù)被調(diào)用了多少次)
23机久、 for in for of 的區(qū)別
ts
1、怎樣表示下面結構
let a = [
[Box,Box],
[Box,Box],
...
]
Array<Box[]>
2赔嚎、裝飾器
3膘盖、反射
4胧弛、接口和抽象類的區(qū)別
5、反射實現(xiàn)依賴注入(為了解決什么問題侠畔,實現(xiàn)過程)
6结缚、對象值的自動推斷
const test = {
aa: {aaa: 1},
bb: {bbb: 2}
}
type TestObj = typeof test;
const fun: <T extends keyof TestObj>(key: T) => TestObj[T] = key => test[key];
fun('aa'); // 自動推斷為 {aaa: number}
css布局
1、css權重
2软棺、c3新選擇器
3红竭、less的特性
4、記得小東西 多使用偽類
5喘落、吸頂實現(xiàn)
6茵宪、內(nèi)容過長footer跟隨內(nèi)容,內(nèi)容很少footer就在屏幕下面 (flex實現(xiàn))
項目
1瘦棋、項目的架構
2稀火、項目中遇到問題怎樣解決
3、項目優(yōu)化赌朋、首屏優(yōu)化憾股, 骨架屏
4、提交了幾個commit箕慧, 線上緊急bug如何處理(考Git)
狀態(tài)管理工具
1服球、vuex, redux, vuex和redux的區(qū)別
2颠焦、談談你對rxjs的理解
webpack
1斩熊、為什么要用loader,它解析原理
2伐庭、優(yōu)化
3粉渠、那些常用的配置(入口,出口圾另,loader霸株,plugin,devserve等)
node
1集乔、事件循環(huán)機制 eventloop
手寫題
1去件、 千分位(隔三位插個逗號)
- var a = '123456789'; => a = '123,456,789,'
function toThounsandInsertStr(str: string): string {
let result: string = '';
let rule: RegExp = /\d{3}$/;
while (rule.test(str)) {
result = RegExp.lastMatch + result;
if (str != RegExp.lastMatch) {
result = ',' + result;
}
str = RegExp.leftContext;
}
return str + result;
}
toThounsandInsertStr('1234567') // 1,234,567
toThounsandInsertStr('123') // 123
toThounsandInsertStr('1') //1
2扰路、 碰到a就剔除字符串里面的 a
和 a前面的數(shù)字
- var a = '12
3a
456a
789aa
'; => a = '12457'
let _arr = a.split('');
for(let i = 0; i < _arr.length; i++) {
let start = 0; let n = 2;
if(_arr[i] == 'a') {
start = i -1 < 0? 0: i -1;
n = i - 1 < 0? 1: 2;
_arr.splice(start, n);
i = n == 2 ? i - 2 : 0;
}
}
console.log(_arr.join(''))
3尤溜、 一個請求在 delay函數(shù)延遲過后發(fā)送,結果可能成功也可能失敗汗唱,如果失敗就重復發(fā)送宫莱,重復n次過后還是失敗,結束發(fā)送返回錯誤
- 請求函數(shù) query, 成功{succ: true}, 失敗{succ: false}
- delay函數(shù) 本身返回一個promise
function delay(t) {
console.log('延遲執(zhí)行開始')
return new Promise(resolve => {
setTimeout(() => {
console.log('延遲完畢')
resolve()
}, t)
})
}
function query() {
console.log('請求開始')
return new Promise(resolve => {
setTimeout(() => {
console.log('1秒失敗哩罪,請求完畢')
resolve({succ: false})
},1000)
})
}
async function repeatQuery(delayTime, n) {
await delay(delayTime)
let res = await query().then(data => data);
console.log(12312312, res)
if(res.succ) {
return res
} else {
if (n <= 0) {
return
}
return await repeatQuery(delayTime, --n)
}
}
repeatQuery(2000, 5).then(res => {
console.log(111, res)
})
4授霸、數(shù)組轉(zhuǎn)樹
var a = [
{id: 1, pid: 0, name: '上海市' },
{id: 2, pid: 1, name: '寶山'},
{id: 3, pid: 1, name: '普陀'},
{id: 4, pid: 0, name: '北京'},
{id: 5, pid: 4, name: '朝陽'},
{id: 6, pid: 4, name: '五環(huán)'},
{id: 7, pid: 2, name: '鎮(zhèn)平'},
{id: 8, pid: 2, name: '寶山'},
]
//轉(zhuǎn)成遞歸樹形式展示
- 思路整理
- 第一次遍歷節(jié)點的時候巡验,會發(fā)現(xiàn)遍歷的子節(jié)點很有可能還沒有父親節(jié)點
- 所以利用第一次遍歷,找出根節(jié)點碘耳,并把所有子節(jié)點統(tǒng)一放到Map中显设,形式為(pid, [pid對應的子節(jié)點...])
- 然后用根節(jié)點的id去匹配Map中的pid對應的子節(jié)點,匹配到的結果數(shù)組也即是當前節(jié)點的children
- 如果有children藏畅,把children當做下一次要匹配的元素找每一個children元素的children
function arrTotree(arr) {
let parentMap = new Map();
// let nodeMap = new Map();
arr.forEach(item => {
// nodeMap.set(item.id, item);
if(parentMap.has(item.pid)) {
let arr = parentMap.get(item.pid);
arr.push(item)
} else {
parentMap.set(item.pid, [item])
}
})
let res = [];
res = parentMap.get(0);
(function loopAddChild(res) {
res.forEach(item => {
if (parentMap.has(item.id)) {
item.children = parentMap.get(item.id);
loopAddChild(item.children)
}
})
})(res)
return res;
}
// 簡化版
function arrToTree(arr) {
let map = new Map();
arr.forEach(item => {
if(!map.has(item.pid)) {
map.set(item.pid, [item])
} else {
let arr = map.get(item.pid);
arr.push(item)
}
})
// 都是指針 第二次遍歷原數(shù)組 匹配id和pid 一樣的話 map取出來當做當前遍歷元素的children
arr.forEach(item => {
if (map.has(item.id)) {
item.children = map.get(item.id);
}
})
// 把頂級的數(shù)組取出來 返回
return map.get(0)
}
5敷硅、 數(shù)組去重(兩種方式功咒, 如果有for循環(huán)愉阎,時間復雜度不能是o(n^2))
var a = [1,2,3,3,2,1,4,5,6,6];
Array.from(new Set([...a]))
// ----
[...new Set([...a])]
// for循環(huán) - 空間換時間
let arr= []
let b = {};
for (let i = 0; i < a.length; i++) {
let curr = a[i];
if (b[curr] >= 0) {
continue
}
b[curr] = i;
arr.push(a[i]);
}
console.log(arr)
6、瀏覽器事件循環(huán)
原則1:先執(zhí)行主任務力奋,然后是微任務(promise)榜旦,最后是宏任務(setTimeout)
原則2:執(zhí)行宏任務的時候碰到微任務,先將其推到task隊列景殷,執(zhí)行完當前宏任務后溅呢,去清空微任務隊列
原則3: 宏任務、微任務先進先出
原則4:new Promise 會立即執(zhí)行 但 resolve是一個異步回調(diào)
原則5:async 返回的是一個Promise
原則6:await 會跳出當前執(zhí)行的 async 函數(shù)體(await 讓出線程)接著執(zhí)行
原則7:當await操作符后面的表達式是一個Promise的時候猿挚,它的返回值咐旧,實際上就是Promise的回調(diào)函數(shù)resolve的參數(shù)
原則8:謹記上面 分析完下面三道題 就無敵了
題1
Promise.resolve().then(function promise1 () {
console.log('promise1');
})
setTimeout(function setTimeout1 (){
console.log('setTimeout1')
Promise.resolve().then(function promise2 () {
console.log('promise2');
})
}, 0)
Promise.resolve().then(function promise1 () {
console.log('promise3');
})
setTimeout(function setTimeout2 (){
console.log('setTimeout2')
}, 0)
題2
setTimeout(() => {
console.log(1)
})
log()
function log() {
setTimeout(() => {
console.log(2)
setTimeout(() => {
console.log(3)
})
})
}
var a = new Promise(resolve => {
setTimeout(() => {
console.log(4)
})
resolve(() => {
setTimeout(() => {
console.log(5)
setTimeout(() => {
console.log(6)
})
})
})
})
setTimeout(() => {
console.log(7)
})
a.then((fn: any) => {
fn()
setTimeout(() => {
console.log(8)
})
})
題3
console.log('1')
async function async1() {
await async2()
console.log('2')
}
async function async2() {
await async3()
console.log('3')
}
async function async3() {
console.log('4')
}
async1()
setTimeout(function () {
console.log('5')
}, 0)
new Promise(resolve => {
console.log('6')
resolve()
}).then(function () {
console.log('7')
return new Promise(resolve => {
console.log('8')
resolve()
})
}).then(function () {
console.log('9')
})
console.log('10')
7、一個數(shù)組中有一系列的整數(shù) 例如 [1绩蜻,2铣墨,-3,4办绝,5伊约,-3,4孕蝉,-6]屡律,利用一個for循環(huán)在數(shù)組中找出連續(xù)相加和最大的一段 [4,5,-3,4] 和為 10
var a = [6, -3, -2, 7, -15, 1, 2, 2];
var b = [1, -2, 2, -1, 4, 5, -3, 4, -1, -2];
function findSum(arr) {
if (arr.length < 0) return 0;
let maxSum = 0;
let temSum = 0;
let resArr = []
let originIndex = 0
let spliceIndex = 0
for (let i = 0; i < arr.length; i++) {
temSum += arr[i];
resArr.push(arr[i])
if (temSum > maxSum) {
maxSum = temSum;
spliceIndex = i - originIndex
}
if(temSum < 0) {
temSum = 0;
resArr = []
originIndex = i
}
}
resArr.splice(spliceIndex, resArr.length - 1)
return {
maxSum,
resArr
}
}
// 簡單測了下 好像是對的...
console.log(findSum(a));
console.log(findSum(b));
8、一個牧場降淮,有一個母牛超埋, 2年后母牛會生一頭母牛和一頭公牛,3年只生一頭公牛佳鳖,5年母牛會死纳本,4年公牛也會死,N年后這個牧場里面有多少只牛
9腋颠、 如何讓if(a == 1 && a == 2 && a == 3 ) 為true
10繁成、用js打印楊輝三角形
11、微信搶紅包邏輯
12淑玫、找出一個單詞在字典中所有字母一樣的單詞巾腕, 如 god -> dog (查字典)面睛, 給出思路
13、實現(xiàn)一個無線可調(diào)用的函數(shù)用來做加法運算 add(1)(2)(3)()
---- 6
function add(num, prevSum) {
let result = prevSum || 0
return num ? function (nextNum) {
result = result + num
return add(nextNum, result)
} : result
}
let a = add(1)(2)(3)()
console.log(a)
// 如果非要求柯里化尊搬,可以用arguments
14叁鉴、使用Promise自身特性,實現(xiàn)每隔兩秒順序打印數(shù)組
- 正常思路都是在一個
async
的方法里面用for循環(huán)await
- 這里運用 Promise自身可鏈式調(diào)用的特性
const list: number[] = [1, 2, 3]
function a(i: number): ProNum {
return new Promise((resolve) => {
setTimeout(() => {
console.log(i)
resolve(i)
}, 2000)
})
}
var p: ProNum = Promise.resolve(0)
function test (i = 0) {
if (i === list.length) return
p = p.then(() => a(list[i]))
test(i+1)
}
test(0)
type ProNum = Promise<number>
15佛寿、 合并兩個有序數(shù)組
function mergeTwoOrderArr(...chunk: number[][]): number[] {
const [arr1, arr2] = chunk;
let tem = Array.from(arr1)
let i = arr1.length - 1;
let j = arr2.length - 1;
let tail = arr1.length + arr2.length - 1;
while (j >= 0) {
if (arr1[i] > arr2[j]) {
tem[tail] = arr1[i]
i--
} else {
tem[tail] = arr2[j]
j--
}
tail --
}
return tem
}
其他
1幌墓、未來幾年的職業(yè)計劃
2、為什么選擇前端
3冀泻、 學習前端技術的途徑
4常侣、 自身優(yōu)缺點
5、對未來公司有什么要求
6弹渔、開發(fā)項目中遇到了什么讓你感覺最驕傲的事情
7胳施、你對我們公司有什么想要了解的
8、為什么離職
9肢专、講一下你最近在做的項目