座標杭州,18年畢業,算上實習一年半開發經驗。是外派的面試,後面兩面都是阿里的面試官。
本來是給我發的線上測評,但是那邊伺服器出現問題,我一直打不開網頁,最後只好以電話問答的形式。下面我寫的大部分都是測評裡的題目,部分是電話裡新增的題目。。。
-
儘量使用盡可能多的方式實現子元素的垂直水平居中
<div class="father"> <div class="child"> </div> </div> <style> .father { width: 300px; height: 300px; } .child { } </style> 複製程式碼
child分很多種情況,大致說一下
- 行內元素:text-align + line-height
.father{
text-align: center;
line-height: 300px;
}
複製程式碼
- 定寬定高:absolute + margin
.father{
position: relative;
}
.child{
position: absolute;
top: 50%;
left: 50%;
margin: -150px 0 0 -150px;
}
/* 或者 */
.child{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
複製程式碼
- 不定高:absolute + translate
.father{
position: relative;
}
.child{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
複製程式碼
- 不定高:flex
.father{
display: flex;
}
.child{
margin:auto;
}
/* 或者 */
.child{
justify-content: center;
align-items: center;
}
複製程式碼
- table方式:
.father{
display: table;
}
.child{
display: table-cell;
text-align: center;
vertical-align: middle;
}
複製程式碼
-
儘可能多的方式實現如下三欄佈局,要求 .main 在中間顯示
<div class="container">
<div class="main"></div>
<div class="sub"></div>
<div class="extra"></div>
</div>
複製程式碼
- 浮動
- flex佈局:利用order屬性(排序,這個沒答上來)
- gird佈局:grid-template-areas
-
執行下面的程式碼,輸出結果是什麼?
console.log(+false) // 0, 這裡是一元運算子進行的弱型別轉換,相對應的 +true 則返回 1
console.log('1' + 2 + '3' + 4) // '1234' 遇到字串就會拼接
console.log(4 + 3 + 2 + '1') // '91' 先加在一起再拼接
複製程式碼
-
執行下面的程式碼,輸出什麼?
var x = 3;
var foo = {
x: 2,
baz: {
x: 1,
bar: function() {
return this.x;
}
}
}
var go = foo.baz.bar;
console.log(go()); // 3
console.log(foo.baz.bar()); // 1
複製程式碼
這題考的是this的指向:
this由呼叫者提供,由呼叫函式的方式來決定。如果是一個物件呼叫的函式,則this指向該物件,比如
foo.baz.bar()
。如果函式獨立呼叫比如go()
,那麼該函式內部的this,則指向undefined。但是在非嚴格模式中,它會被自動指向全域性物件window。
-
實現以下函式,使得輸入的字串逆序輸出
function reverse(str) {
let res = str.split('');
return res.reverse().join('');
}
reverse('hello world!'); // output: '!dlrow olleh'
複製程式碼
進階問題
'hello world!'.reverse(); // output: '!dlrow olleh'
複製程式碼
- 這個問題需要給String的原型上新增方法,但是要考慮有一些改造:
String.prototype.reverse = function reverse() {
let res = this.split('');
return res.reverse().join('');
}
複製程式碼
-
實現sleep 函式
要求用法:
/**
- 使當前執行的非同步操作(promise 或者 async)停止等待若干秒
-
- @param ms */
(async () => {
console.log('hello')
await sleep(2000) // 等待兩秒
console.log('world')
})()
複製程式碼
const sleep = (ms) => {
new Promise(resolve, reject) {
setTimeOut(() => {
resolve(); // 大致這樣?
}, ms)
}
}
複製程式碼
-
實現throttle 節流函式
用法:
const throFun = () => console.log('hello'); const thro = throttle(throFun, 300); document.body.onscroll = () => { thro(); // 呼叫至少間隔 300 毫秒才會觸發一次 } 複製程式碼
/** - 頻率控制,返回函式連續呼叫時,action 執行頻率限定為 1次 / delay - @param delay {number} 延遲時間,單位毫秒 - @param action {function} 請求關聯函式,實際應用需要呼叫的函式 - @return {function} 返回客戶呼叫函式 */ function throttle(action, delay) { var previous = 0; // 使用閉包返回一個函式並且用到閉包函式外面的變數previous return function() { var _this = this; var args = arguments; var now = new Date(); if(now - previous > delay) { action.apply(_this, args); previous = now; } } } 複製程式碼
-
實現debounce 防抖函式
用法:
const throFun = () => console.log('hello'); const thro = debounce(throFun, 300); document.body.onscroll = () => { thro(); // 若一直呼叫則不會執行,空閒時間大於 300 毫秒才會執行 } 複製程式碼
/** - 空閒控制 返回函式連續呼叫時,空閒時間必須大於或等於 delay,action 才會執行 - @param delay {number} 空閒時間,單位毫秒 - @param action {function} 請求關聯函式,實際應用需要呼叫的函式 - @return {function} 返回客戶呼叫函式 */ function debounce(action, delay) { var timer; // 維護一個 timer return function () { var _this = this; // 取debounce執行作用域的this var args = arguments; if (timer) { clearTimeout(timer); } timer = setTimeout(function () { action.apply(_this, args); // 用apply指向呼叫debounce的物件,相當於_this.action(args); }, delay); }; } 複製程式碼
-
陣列去重有哪些方法?
const arr = [1,2,3,4,4,3,2,1];
// 方法一:new Set ES6
return [...new Set(arr)]; // 這裡又問到我...的用法
// 方法二:雙層for迴圈 (然後說這樣效能不好,讓我只用一層for迴圈的方法)
function unique(arr){
var res=[];
for (var i = 0; i < arr.length; i++) {
for (var j = i+1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
++ i;
j = i;
}
}
res.push(arr[i]);
}
return res;
}
// 方法三:單層for迴圈 + indexOf
function unique(array){
var res = [];
for(var i = 0; i < array.length; i++) {
//如果當前陣列的第i項在當前陣列中第一次出現的位置是i,才存入陣列;否則代表是重複的
if (array.indexOf(array[i]) === i) {
res.push(array[i])
}
}
return res;
}
// 方法三點三:或者這樣
function unique(array){
let res = [];
for(var i = 0; i < array.length; i++) {
if (res.indexOf(array[i]) === -1) {
res.push(array[i]);
}
}
return res;
}
// 方法四:面試官說如果可以容忍改變原有陣列的情況下,怎麼改進效能更好
function unique(array){
// 注意這裡一定要倒敘for迴圈,否則會出現問題
for(var i = array.length - 1; i > 0; i--) {
if (array.indexOf(array[i]) !== i) {
array.splice(i, 1);
}
}
// 因為少宣告一個變數,節省了記憶體空間(雖然可以忽略不計,但是面試嘛~)
return array;
}
複製程式碼
-
場景題,考察事件代理,事件監聽,DOM自定義屬性等
題目描述:
- 網頁中有一個元素A,它有個data-href屬性,裡面存放一個連結地址?
- 實現一個函式,當任意點選時,如果點選的元素就是A或其上層節點中找到A,則進行連結跳轉
實現思路:
- 首先給window新增點選事件的監聽,然後先宣告一箇中間變數targetNode記錄節點
- 然後迴圈判斷當前節點targetNode是否存在data-href屬性
- 如果存在則進行跳轉,break。不存在則將該節點的父節點賦值給targetNode
- 一直迴圈到判斷targetNode是最外層節點為止
面試過後整理的程式碼:
window.addEventListener('click', (e) => {
let targetNode = e.target
while (targetNode !== document) { // 只要當前節點不是最外層document
console.log(targetNode)
if (targetNode.getAttribute('data-href')) { // 其實用hasAttribute更合適
window.open(targetNode.dataset.href)
break
} else { // 沒找到就繼續往上找
targetNode = targetNode.parentNode
}
}
})
複製程式碼
總結:
- 感覺這道題出的很好,回答過程中面試官也一直引導我的思路,比如最開始我想到判斷節點是否為上下級關係的方法用DOM的
contains()
方法,然後面試官考慮效能,最好用原生api。然後我就說用parentNode。後來我查了一下MDN,發現contains
這個方法就是原生的api,IE5以上就支援了: 但是這也不是重點,重點是用contains這個方法不能實現這個場景,因為你需要父節點(上層節點)是已知的。但這個場景是通過已知子節點(點選事件返回的target)來向上尋找節點。 - 我說到用dataset獲取自定義屬性的時候,面試官說考慮到相容性,有沒有別的方法。我回答
getAttribute()
。 - 在說怎麼一層一層的往上找節點的時候,最開始我想到了用遞迴呼叫函式,面試官當即打斷我說沒有必要,而且浪費效能。然後提示我說有什麼迴圈的方法。最後想到了while
-
其他問題
- ES6陣列有哪些方法
- React使用中用過哪些狀態管理工具,緊接著問了redux和mobx的區別,面試遇到三四次了,故總結一下:
1.Redux 鼓勵一個應用只用一個 Store,Mobx 鼓勵使用多個 Store; 2.Redux 是函數語言程式設計,而Mobx的模式是物件導向的; 3.Redux 使用“拉”的方式使用資料,這一點和 React是一致的,但 Mobx 使用“推”的方式使用資料; 4.Redux 鼓勵資料正規化化,減少冗餘,Mobx 容許資料冗餘,但同樣能保持資料一致。 5.Redux更嚴格,必須呼叫reducer觸發action來改變state, Mobx 最初的一個賣點就是直接修改資料,但是實踐中大家還是發現這樣無組織無紀律不好,所以後來 Mobx 還是提供了 action 的概念。和 Redux 的 action 有點不同,Mobx 中的 action 其實就是一個函式,不需要做 dispatch。如果想強制要求使用 action,禁止直接修改 observable 資料,使用 Mobx 的 configure,如下:
import {configure} from 'mobx'; configure({enforceActions: true}); 複製程式碼
- 讓講了一下react的虛擬DOM,簡單講一下diff演算法原理
- React中key的作用