本週面試題一覽:
- 實現 Promise.race 方法
- JSONP 原理及簡單實現
- 實現一個陣列去重的方法
- 清除浮動的方法有哪些
- 編寫一個通用的柯里化函式 currying
更多優質文章可戳: github.com/YvetteLau/B…
20. 實現 Promise.race 方法
在實現 Promise.race
方法之前,我們首先要知道 Promise.race
的功能和特點,因為在清楚了 Promise.race
功能和特點的情況下,我們才能進一步去寫實現。
Promise.race 功能
Promise.race(iterable)
返回一個 promise,一旦 iterable
中的一個 promise
狀態是 fulfilled
/ rejected
,那麼 Promise.race
返回的 promise
狀態是 fulfilled
/ rejected
.
let p = Promise.race([p1, p2, p3]);
複製程式碼
只要p1、p2、p3之中有一個例項率先改變狀態,p的狀態就跟著改變。那個率先改變的 Promise
例項的返回值,就傳遞給 p 的回撥函式。
Promise.race 的特點
Promise.race 的返回值是一個 promise 例項
- 如果傳入的引數為空的可迭代物件,那麼
Promise.race
返回的promise
永遠是pending
態 - 如果傳入的引數中不包含任何
promise
,Promise.race
會返回一個處理中(pending)的promise
- 如果
iterable
包含一個或多個非promise
值或已經解決的promise,則Promise.race
將解析為iterable
中找到的第一個值。
Promise.race 的實現
Promise.race = function (promises) {
//promises傳入的是可迭代物件(省略引數合法性判斷)
promises = Array.from(promises);//將可迭代物件轉換為陣列
return new Promise((resolve, reject) => {
if (promises.length === 0) {
//空的可迭代物件;
//用於在pending態
} else {
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then((data) => {
resolve(data);
}).catch((reason) => {
reject(reason);
})
}
}
});
}
複製程式碼
21. JSONP原理及簡單實現
儘管瀏覽器有同源策略,但是 <script>
標籤的 src
屬性不會被同源策略所約束,可以獲取任意伺服器上的指令碼並執行。jsonp
通過插入 script
標籤的方式來實現跨域,引數只能通過 url
傳入,僅能支援 get
請求。
實現原理:
- Step1: 建立 callback 方法
- Step2: 插入 script 標籤
- Step3: 後臺接受到請求,解析前端傳過去的 callback 方法,返回該方法的呼叫,並且資料作為引數傳入該方法
- Step4: 前端執行服務端返回的方法呼叫
jsonp原始碼實現
function jsonp({url, params, callback}) {
return new Promise((resolve, reject) => {
//建立script標籤
let script = document.createElement('script');
//將回撥函式掛在 window 上
window[callback] = function(data) {
resolve(data);
//程式碼執行後,刪除插入的script標籤
document.body.removeChild(script);
}
//回撥函式加在請求地址上
params = {...params, callback} //wb=b&callback=show
let arrs = [];
for(let key in params) {
arrs.push(`${key}=${params[key]}`);
}
script.src = `${url}?${arrs.join('&')}`;
document.body.appendChild(script);
});
}
複製程式碼
使用:
function show(data) {
console.log(data);
}
jsonp({
url: 'http://localhost:3000/show',
params: {
//code
},
callback: 'show'
}).then(data => {
console.log(data);
});
複製程式碼
服務端程式碼(node):
//express啟動一個後臺服務
let express = require('express');
let app = express();
app.get('/show', (req, res) => {
let {callback} = req.query; //獲取傳來的callback函式名,callback是key
res.send(`${callback}('Hello!')`);
});
app.listen(3000);
複製程式碼
22. 實現一個陣列去重的方法
法1: 利用ES6新增資料型別 Set
Set
類似於陣列,但是成員的值都是唯一的,沒有重複的值。
function uniq(arry) {
return [...new Set(arry)];
}
複製程式碼
法2: 利用 indexOf
function uniq(arry) {
var result = [];
for (var i = 0; i < arry.length; i++) {
if (result.indexOf(arry[i]) === -1) {
//如 result 中沒有 arry[i],則新增到陣列中
result.push(arry[i])
}
}
return result;
}
複製程式碼
法3: 利用 includes
function uniq(arry) {
var result = [];
for (var i = 0; i < arry.length; i++) {
if (!result.includes(arry[i])) {
//如 result 中沒有 arry[i],則新增到陣列中
result.push(arry[i])
}
}
return result;
}
複製程式碼
法4:利用 reduce
function uniq(arry) {
return arry.reduce((prev, cur) => prev.includes(cur) ? prev : [...prev, cur], []);
}
複製程式碼
法5:利用 Map
function uniq(arry) {
let map = new Map();
let result = new Array();
for (let i = 0; i < arry.length; i++) {
if (map.has(arry[i])) {
map.set(arry[i], true);
} else {
map.set(arry[i], false);
result.push(arry[i]);
}
}
return result;
}
複製程式碼
23. 清除浮動的方法有哪些?
當容器的高度為auto,且容器的內容中有浮動(float為left或right)的元素,在這種情況下,容器的高度不能自動伸長以適應內容的高度,使得內容溢位到容器外面而影響(甚至破壞)佈局的現象。這個現象叫浮動溢位,為了防止這個現象的出現而進行的CSS處理,就叫CSS清除浮動。
<style>
.inner {
width: 100px;
height: 100px;
float: left;
}
</style>
<div class='outer'>
<div class='inner'></div>
<div class='inner'></div>
<div class='inner'></div>
</div>
複製程式碼
1. 利用 clear
屬性
在 <div class='outer'>
內建立一個空元素,對其設定 clear: both;
的樣式。
- 優點:簡單,程式碼少,瀏覽器相容性好。
- 缺點:需要新增大量無語義的html元素,程式碼不夠優雅,後期不容易維護。
2. 利用 clear
屬性 + 偽元素
.outer:after{
content: '';
display: block;
clear: both;
visibility: hidden;
height: 0;
}
複製程式碼
IE8以上和非IE瀏覽器才支援:after,如果想要支援IE6、7,需要給 outer
元素,設定樣式 zoom: 1
;
3. 利用 BFC 佈局規則
根據 BFC 的規則,計算 BFC 的高度時,浮動元素也參與計算。因此清除浮動,只需要觸發一個BFC即可。
可以使用以下方法來觸發BFC
- position 為 absolute 或 fixed
- overflow 不為 visible 的塊元素
- display 為 inline-block, table-cell, table-caption
如:
.outer {
overflow: hidden;
}
複製程式碼
注意使用 display: inline-block
會產生間隙。
24. 編寫一個通用的柯里化函式 currying
在開始之前,我們首先需要搞清楚函式柯里化的概念。
函式柯里化是把接受多個引數的函式變換成接受一個單一引數(最初函式的第一個引數)的函式,並且返回接受餘下的引數而且返回結果的新函式的技術。
const currying = (fn, ...args) =>
args.length < fn.length
//引數長度不足時,重新柯里化該函式,等待接受新引數
? (...arguments) => currying(fn, ...args, ...arguments)
//引數長度滿足時,執行函式
: fn(...args);
複製程式碼
function sumFn(a, b, c) {
return a + b + c;
}
var sum = currying(sumFn);
console.log(sum(2)(3)(5));//10
console.log(sum(2, 3, 5));//10
console.log(sum(2)(3, 5));//10
console.log(sum(2, 3)(5));//10
複製程式碼
函式柯里化的主要作用:
- 引數複用
- 提前返回 – 返回接受餘下的引數且返回結果的新函式
- 延遲執行 – 返回新函式,等待執行
參考文章:
[1] CSS-清除浮動
[2] 詳解JS函式柯里化
[3] JavaScript陣列去重
謝謝各位小夥伴願意花費寶貴的時間閱讀本文,如果本文給了您一點幫助或者是啟發,請不要吝嗇你的贊和Star,您的肯定是我前進的最大動力。 github.com/YvetteLau/B…