幾個(gè)常見(jiàn)面試題,工作中也經(jīng)常用到
?
01 什么是防抖和節(jié)流,他們的應(yīng)用場(chǎng)景有哪些
?在 Issue 中交流與討論: 01 什么是防抖和節(jié)流,他們的應(yīng)用場(chǎng)景有哪些[1]
?
防抖 (debounce)
防抖,顧名思義,防止抖動(dòng),以免把一次事件誤認(rèn)為多次,敲鍵盤(pán)就是一個(gè)每天都會(huì)接觸到的防抖操作。
想要了解一個(gè)概念,必先了解概念所應(yīng)用的場(chǎng)景。在 JS 這個(gè)世界中,有哪些防抖的場(chǎng)景呢
登錄、發(fā)短信等按鈕避免用戶點(diǎn)擊太快,以致于發(fā)送了多次請(qǐng)求,需要防抖 調(diào)整瀏覽器窗口大小時(shí),resize 次數(shù)過(guò)于頻繁,造成計(jì)算過(guò)多,此時(shí)需要一次到位,就用到了防抖 文本編輯器實(shí)時(shí)保存,當(dāng)無(wú)任何更改操作一秒后進(jìn)行保存
代碼如下,可以看出來(lái)「防抖重在清零?clearTimeout(timer)」
function?debounce?(f,?wait)?{
??let?timer
??return?(...args)?=>?{
????clearTimeout(timer)
????timer?=?setTimeout(()?=>?{
??????f(...args)
????},?wait)
??}
}
節(jié)流 (throttle)
節(jié)流,顧名思義,控制水的流量。控制事件發(fā)生的頻率,如控制為 1s 發(fā)生一次,甚至 1 分鐘發(fā)生一次。與服務(wù)端(server)及網(wǎng)關(guān)(gateway)控制的限流 (Rate Limit) 類(lèi)似。
scroll?事件,每隔一秒計(jì)算一次位置信息等瀏覽器播放事件,每個(gè)一秒計(jì)算一次進(jìn)度信息等 input 框?qū)崟r(shí)搜索并發(fā)送請(qǐng)求展示下拉列表,每隔一秒發(fā)送一次請(qǐng)求 (也可做防抖)
代碼如下,可以看出來(lái)「節(jié)流重在加鎖?timer=timeout」
function?throttle?(f,?wait)?{
??let?timer
??return?(...args)?=>?{
????if?(timer)?{?return?}
????timer?=?setTimeout(()?=>?{
??????f(...args)
??????timer?=?null
????},?wait)
??}
}
總結(jié) (簡(jiǎn)要答案)
防抖:防止抖動(dòng),單位時(shí)間內(nèi)事件觸發(fā)會(huì)被重置,避免事件被誤傷觸發(fā)多次。「代碼實(shí)現(xiàn)重在清零? clearTimeout」。防抖可以比作等電梯,只要有一個(gè)人進(jìn)來(lái),就需要再等一會(huì)兒。業(yè)務(wù)場(chǎng)景有避免登錄按鈕多次點(diǎn)擊的重復(fù)提交。節(jié)流:控制流量,單位時(shí)間內(nèi)事件只能觸發(fā)一次,與服務(wù)器端的限流 (Rate Limit) 類(lèi)似。「代碼實(shí)現(xiàn)重在開(kāi)鎖關(guān)鎖? timer=timeout; timer=null」。節(jié)流可以比作過(guò)紅綠燈,每等一個(gè)紅燈時(shí)間就可以過(guò)一批。
02 在前端開(kāi)發(fā)中,如何獲取瀏覽器的唯一標(biāo)識(shí)
??更多描述: 如何獲取瀏覽器的唯一標(biāo)識(shí),原理是什么??
?在 Issue 中交流與討論: 02 在前端開(kāi)發(fā)中,如何獲取瀏覽器的唯一標(biāo)識(shí)[2]
?
由于不同的系統(tǒng)顯卡繪制?canvas?時(shí)渲染參數(shù)、抗鋸齒等算法不同,因此繪制成圖片數(shù)據(jù)的?CRC?校驗(yàn)也不一樣。
function?getCanvasFp?()?{
??const?canvas?=?document.getElementById('canvas')
??const?ctx?=?canvas.getContext('2d')
??ctx.font?=?'14px?Arial'
??ctx.fillStyle?=?'#ccc'
??ctx.fillText('hello,?shanyue',?2,?2)
??return?canvas.toDataURL('image/jpeg')
}
因此根據(jù)?canvas?可以獲取瀏覽器指紋信息。
繪制? canvas,獲取?base64?的 dataurl對(duì) dataurl 這個(gè)字符串進(jìn)行? md5?摘要計(jì)算,得到指紋信息
但是對(duì)于常見(jiàn)的需求就有成熟的解決方案,若在生產(chǎn)環(huán)境使用,可以使用以下庫(kù)
fingerprintjs2[3]
它依據(jù)以下信息,獲取到瀏覽器指紋信息,「而這些信息,則成為?component」
canvaswebglUserAgentAudioContext對(duì)新式 API 的支持程度等
requestIdleCallback(function?()?{
??Fingerprint2.get((components)?=>?{
????const?values?=?components.map((component)?=>?component.value)
????const?fp?=?Fingerprint2.x64hash128(values.join(''),?31)
??})
})
在?fingerprintjs2?中,對(duì)于?component?也有分類(lèi)
browser independent component[4]:有些? component?同一設(shè)備跨瀏覽器也可以得到相同的值,有些獨(dú)立瀏覽器,得到不同的值stable component[5]: 有些? component?刷新后值就會(huì)發(fā)生變化,稱(chēng)為不穩(wěn)定組件
在實(shí)際業(yè)務(wù)中,可根據(jù)業(yè)務(wù)選擇合適的組件
const?options?=?{
??excludes:?{userAgent:?true,?language:?true}
}
簡(jiǎn)答
根據(jù)?canvas?可以獲取瀏覽器指紋信息
繪制? canvas,獲取?base64?的 dataurl對(duì) dataurl 這個(gè)字符串進(jìn)行? md5?摘要計(jì)算,得到指紋信息
若在生產(chǎn)環(huán)境使用,可以使用 fingerprintjs2[6],根據(jù)業(yè)務(wù)需求,如單設(shè)備是否可跨瀏覽器,以此選擇合適的?component
03 在服務(wù)端應(yīng)用中如何獲得客戶端 IP
?在 Issue 中交流與討論: 03 在服務(wù)端應(yīng)用中如何獲得客戶端 IP[7]
?
「如果有?x-forwarded-for?的請(qǐng)求頭,則取其中的第一個(gè) IP,否則取建立連接 socket 的 remoteAddr?!?/strong>
而?x-forwarded-for?基本已成為了基于 proxy 的標(biāo)準(zhǔn) HTTP 頭,格式如下,可見(jiàn)第一個(gè) IP 代表其真實(shí)的 IP,可以參考 MDN X-Forwarded-For[8]
X-Forwarded-For:?203.0.113.195,?70.41.3.18,?150.172.238.178
X-Forwarded-For:?,?,?
以下是?koa?獲取 IP 的方法
??get?ips()?{
????const?proxy?=?this.app.proxy;
????const?val?=?this.get(this.app.proxyIpHeader);
????let?ips?=?proxy?&&?val
????????val.split(/\s*,\s*/)
??????:?[];
????if?(this.app.maxIpsCount?>?0)?{
??????ips?=?ips.slice(-this.app.maxIpsCount);
????}
????return?ips;
??},
??get?ip()?{
????if?(!this[IP])?{
??????this[IP]?=?this.ips[0]?||?this.socket.remoteAddress?||?'';
????}
????return?this[IP];
??},
參見(jiàn)源碼: https://github.com/koajs/koa/blob/master/lib/request.js#L433
04 js 如何全部替代一個(gè)子串為另一個(gè)子串
??更多描述: 假設(shè)有一個(gè)字符串 `hello. hello. hello. ` 需要替換為 `AAA`,即把 `hello. ` 替換為 `A`??
?在 Issue 中交流與討論: 04 js 如何全部替代一個(gè)子串為另一個(gè)子串[9]
?
如果需要全量替換字符串,可以使用?String.prototype.replace(re, replacer),其中正則表達(dá)式需要開(kāi)啟?global?flag
const?s?=?'foo?foo?foo'
s.replce(/foo/g,?'bar')
那如題中,「是否可以使用正則表達(dá)式來(lái)替代子串」
答:「不可以,因?yàn)槭褂米哟畼?gòu)建正則時(shí),有可能有特殊字符,就有可能出現(xiàn)問(wèn)題」,如下
//?期待結(jié)果:?'AhelloX?hello3?'
>?'hello.?helloX?hello3?'.replace(new?RegExp('hello.?',?'g'),?'A')
"AAA"
而在?javascript?中替換子串只能使用一種巧妙的辦法:str.split('foo').join('bar')
>?'hello.?hello.?hello.?'.split('hello.?').join('A')
"AAA"
真是一個(gè)巧(笨)妙(拙)的辦法啊?。。。?!「大概 TC39 也意識(shí)到了一個(gè)問(wèn)題,于是出了一個(gè)新的 API」,在?ESNext?中
String.prototype.replaceAll()
'aabbcc'.replaceAll('b',?'.');
//?'aa..cc'
詳細(xì)文檔在 String.prototype.replaceAll[10]
總結(jié)(及直接答案)
兩種辦法
str.split('foo').join('bar')str.replaceAll('foo', 'bar'),在?ESNext?中,目前支持性不好
05 如何獲取一個(gè)進(jìn)程的內(nèi)存并監(jiān)控
??更多描述: 在編寫(xiě)腳本時(shí),有時(shí)會(huì)出現(xiàn)內(nèi)存過(guò)大發(fā)生 OOM 的事情,那我們?nèi)绾蔚弥硞€(gè)進(jìn)程的內(nèi)存?另外又如何監(jiān)控它??
?在 Issue 中交流與討論: 05 如何獲取一個(gè)進(jìn)程的內(nèi)存并監(jiān)控[11]
?
通過(guò)?ps?可以獲知一個(gè)進(jìn)程所占用的內(nèi)存
$?ps?-O?rss?-p?3506
??PID???RSS?S?TTY??????????TIME?COMMAND
?3506??6984?S?pts/1????00:00:00?vim
如果要監(jiān)控內(nèi)存,肯定使用對(duì)進(jìn)程萬(wàn)能的命令?pidstat?(PS: 這名字一聽(tīng)就知道是干嘛的)
##?-r?顯示內(nèi)存信息
##?-p?指定?pid
##?1:?每個(gè)一秒打印一次
$?pidstat?-r?-p?3506?1
Linux?3.10.0-957.21.3.el7.x86_64?(shanyue)??????11/04/19????????_x86_64_????????(2?CPU)
20:47:35??????UID???????PID??minflt/s??majflt/s?????VSZ????RSS???%MEM??Command
20:47:36????????0??????3506??????0.00??????0.00??139940???6984???0.18??vim
20:47:37????????0??????3506??????0.00??????0.00??139940???6984???0.18??vim
20:47:38????????0??????3506??????0.00??????0.00??139940???6984???0.18??vim
20:47:39????????0??????3506??????0.00??????0.00??139940???6984???0.18??vim
20:47:40????????0??????3506??????0.00??????0.00??139940???6984???0.18??vim
20:47:41????????0??????3506??????0.00??????0.00??139940???6984???0.18??vim
pidstat?是屬于?sysstat?下的 linux 性能工具,但在 mac 中,如何定位內(nèi)存的變化?此時(shí)可以使用萬(wàn)能的?top/htop
$?htop?-p?31796總結(jié)
簡(jiǎn)而言之,有以下三個(gè)命令
pidstat -rhtop/top -pps -O rss -p
關(guān)于更多指標(biāo)的監(jiān)控可以參考我的文章: linux 各項(xiàng)監(jiān)控指標(biāo)小記[12]
06 CORS 如果需要指定多個(gè)域名怎么辦
?在 Issue 中交流與討論: 06 CORS 如果需要指定多個(gè)域名怎么辦[13]
?
CORS?通過(guò)控制?Access-Control-Allow-Origin?控制哪些域名可以共享資源,取值如下
Access-Control-Allow-Origin:??|?*
其中?*?代表所有域名,origin?代表指定特定域名,那如何設(shè)置多個(gè)域名了?
此時(shí)需要通過(guò)代碼實(shí)現(xiàn),「根據(jù)請(qǐng)求頭中的?Origin?來(lái)設(shè)置響應(yīng)頭?Access-Control-Allow-Origin」,那 Origin 又是什么東西?
請(qǐng)求頭: Origin
并不是所有請(qǐng)求都會(huì)自動(dòng)帶上?Origin,在瀏覽器中帶?Origin?的邏輯如下
如果存在跨域,則帶上? Origin,值為當(dāng)前域名如果不存在跨域,則不帶? Origin
邏輯理清楚后,關(guān)于服務(wù)器中對(duì)于?Access-Control-Allow-Origin?設(shè)置多域名的邏輯也很清晰了
如果請(qǐng)求頭不帶有? Origin,證明未跨域,則不作任何處理如果請(qǐng)求頭帶有? Origin,證明跨域,根據(jù)?Origin?設(shè)置相應(yīng)的?Access-Control-Allow-Origin:
使用偽代碼實(shí)現(xiàn)如下:
//?獲取?Origin?請(qǐng)求頭
const?requestOrigin?=?ctx.get('Origin');
//?如果沒(méi)有,則跳過(guò)
if?(!requestOrigin)?{
??return?await?next();
}
//?設(shè)置響應(yīng)頭
ctx.set('Access-Control-Allow-Origin',?requestOrigin)
Vary: Origin
此時(shí)可以給多個(gè)域名控制 CORS,但此時(shí)假設(shè)有兩個(gè)域名訪問(wèn)?static.shanyue.tech?的跨域資源
foo.shanyue.tech,響應(yīng)頭中返回?Access-Control-Allow-Origin: foo.shanyue.techbar.shanyue.tech,響應(yīng)頭中返回?Access-Control-Allow-Origin: bar.shanyue.tech
看起來(lái)一切正常,但如果中間有緩存怎么辦?
foo.shanyue.tech,響應(yīng)頭中返回?Access-Control-Allow-Origin: foo.shanyue.tech,被 CDN 緩存「 bar.shanyue.tech,因由緩存,響應(yīng)頭中返回?Access-Control-Allow-Origin: foo.shanyue.tech,跨域出現(xiàn)問(wèn)題」
此時(shí),Vary: Origin?就上場(chǎng)了,代表為不同的?Origin?緩存不同的資源
總結(jié) (簡(jiǎn)要答案)
CORS 如何指定多個(gè)域名?
「根據(jù)請(qǐng)求頭中的?Origin?來(lái)設(shè)置響應(yīng)頭?Access-Control-Allow-Origin」,思路如下
總是設(shè)置? Vary: Origin,避免 CDN 緩存破壞 CORS 配置如果請(qǐng)求頭不帶有? Origin,證明未跨域,則不作任何處理如果請(qǐng)求頭帶有? Origin,證明瀏覽器訪問(wèn)跨域,根據(jù)?Origin?設(shè)置相應(yīng)的?Access-Control-Allow-Origin:
使用偽代碼實(shí)現(xiàn)如下
//?獲取?Origin?請(qǐng)求頭
const?requestOrigin?=?ctx.get('Origin');
ctx.set('Vary',?'Origin')
//?如果沒(méi)有,則跳過(guò)
if?(!requestOrigin)?{
??return?await?next();
}
//?設(shè)置響應(yīng)頭
ctx.set('Access-Control-Allow-Origin',?requestOrigin)
?相關(guān)問(wèn)題:如何避免 CDN 為 PC 端緩存移動(dòng)端頁(yè)面[14]
?
07 既然 cors 配置可以做跨域控制,那可以防止 CSRF 攻擊嗎
?在 Issue 中交流與討論: 07 既然 cors 配置可以做跨域控制,那可以防止 CSRF 攻擊嗎?[15]
?
「對(duì) CORS 一點(diǎn)用也沒(méi)有」
「 form?提交不通過(guò)?CORS?檢測(cè)」,你可以在本地進(jìn)行測(cè)試即使通過(guò)? xhr?及?fetch?進(jìn)行提交被 CORS 攔住,「但是對(duì)于簡(jiǎn)單請(qǐng)求而言,請(qǐng)求仍被發(fā)送」,已造成了攻擊
08 如何避免 CDN 為 PC 端緩存移動(dòng)端頁(yè)面
?在 Issue 中交流與討論: 08 如何避免 CDN 為 PC 端緩存移動(dòng)端頁(yè)面[16]
?
如果 PC 端和移動(dòng)端是一套代碼則不會(huì)出現(xiàn)這個(gè)問(wèn)題。「這個(gè)問(wèn)題出現(xiàn)在 PC 端和移動(dòng)端是兩套代碼,卻共用一個(gè)域名?!?/strong>
使用?nginx?配置如下,根據(jù) UA 判斷是否移動(dòng)端,而走不同的邏輯 (判斷 UA 是否移動(dòng)端容易出問(wèn)題)
location / {
// 默認(rèn) PC 端
root /usr/local/website/web;
# 判斷 UA,訪問(wèn)移動(dòng)端
if ( $http_user_agent ~* "(Android|webOS|iPhone|iPad|BlackBerry)" ){
root /usr/local/website/mobile;
}
index index.html index.htm;
}
解決方案通常使用?Vary?響應(yīng)頭,來(lái)控制 CDN 對(duì)不同請(qǐng)求頭的緩存。
「此處可以使用?Vary: User-Agent?,代表如果 User-Agent 不一樣,則重新發(fā)起請(qǐng)求,而非從緩存中讀取頁(yè)面」
Vary: User-Agent
當(dāng)然,User-Agent?實(shí)在過(guò)多,此時(shí)緩存失效就會(huì)過(guò)多。
簡(jiǎn)答
使用?Vary: User-Agent,根據(jù) UA 進(jìn)行緩存。
Vary: User-Agent
但最好不要出現(xiàn)這種情況,PC 端和移動(dòng)端如果是兩套代碼,建議用兩個(gè)域名,理由如下
nginx?判斷是否移動(dòng)端容易出錯(cuò)對(duì)緩存不友好
09 如何實(shí)現(xiàn)表格單雙行條紋樣式
?在 Issue 中交流與討論: 09 如何實(shí)現(xiàn)表格單雙行條紋樣式[17]
?
通過(guò)?css3?中偽類(lèi)?:nth-child?來(lái)實(shí)現(xiàn)。其中?:nth-child(an+b)?匹配下標(biāo)?{ an + b; n = 0, 1, 2, ...}?且結(jié)果為整數(shù)的子元素
nth-child(2n)/nth-child(even): 雙行樣式nth-child(2n+1)/nth-child(odd): 單行樣式
其中?tr?在表格中代表行,實(shí)現(xiàn)表格中單雙行樣式就很簡(jiǎn)單了:
tr:nth-child(2n)?{
??background-color:?red;
}
tr:nth-child(2n+1)?{
??background-color:?blue;
}
同理:
如何匹配最前三個(gè)子元素:? :nth-child(-n+3)如何匹配最后三個(gè)子元素:? :nth-last-child(-n+3)
10 簡(jiǎn)述下 css specificity
?在 Issue 中交流與討論: 10 簡(jiǎn)述下 css specificity[18]
?
css specificity?即 css 中關(guān)于選擇器的權(quán)重,以下三種類(lèi)型的選擇器依次下降
id?選擇器,如?#appclass、attribute?與?pseudo-classes?選擇器,如?.header、[type="radio"]與?:hovertype?標(biāo)簽選擇器和偽元素選擇器,如?h1、p?和?::before
其中通配符選擇器?*,組合選擇器?+ ~ >,否定偽類(lèi)選擇器?:not()?對(duì)優(yōu)先級(jí)無(wú)影響
另有內(nèi)聯(lián)樣式??及?!important(最高) 具有更高的權(quán)重
?`:not` 的優(yōu)先級(jí)影響 - codepen[19]?可以看出?
?:not?對(duì)選擇器的優(yōu)先級(jí)無(wú)任何影響
11 node 中 module.exports 與 exports 有什么區(qū)別
?在 Issue 中交流與討論: 11 node 中 module.exports 與 exports 有什么區(qū)別[20]
?
「一句話:exports?是?module.exports?的引用,如果?exports?沒(méi)有重賦值,則二者沒(méi)有任何區(qū)別」
類(lèi)似如下所示
const?exports?=?module.exports
那如下結(jié)果會(huì)如何導(dǎo)出?
module.exports?=?100
exports?=?3
很顯然會(huì)導(dǎo)出 100,畢竟?exports?進(jìn)行了重賦值。
「那在 node 源碼中如何實(shí)現(xiàn)的呢?」?從源碼里可以看出?「exports」?的實(shí)質(zhì)

詳見(jiàn)源碼: https://github.com/nodejs/node/blob/master/lib/internal/modules/cjs/loader.js#L1252,可以看出符合猜想
眾所周知,node 中所有的模塊代碼都被包裹在這個(gè)函數(shù)中
(function(exports,?require,?module,?__filename,?__dirname)?{
??exports.a?=?3
});
而以下源碼指出,exports?是如何得來(lái)
const?dirname?=?path.dirname(filename);
const?require?=?makeRequireFunction(this,?redirects);
let?result;
//?從這里可以看出來(lái)?exports?的實(shí)質(zhì)
const?exports?=?this.exports;
const?thisValue?=?exports;
const?module?=?this;
if?(requireDepth?===?0)?statCache?=?new?Map();
if?(inspectorWrapper)?{
??result?=?inspectorWrapper(compiledWrapper,?thisValue,?exports,
????????????????????????????require,?module,?filename,?dirname);
}?else?{
??//?這里是模塊包裝函數(shù)
??result?=?compiledWrapper.call(thisValue,?exports,?require,?module,
????????????????????????????????filename,?dirname);
}
12 如何獲取當(dāng)前系統(tǒng)中的在線用戶數(shù) (并發(fā)用戶數(shù))
??更多描述: 一些 SaaS 系統(tǒng)基于 Pricing 的考慮,會(huì)限制團(tuán)隊(duì)人數(shù)及同時(shí)在線數(shù),如何實(shí)現(xiàn)??
?在 Issue 中交流與討論: 12 如何獲取當(dāng)前系統(tǒng)中的在線用戶數(shù) (并發(fā)用戶數(shù))[21]
?
?一些 SaaS 系統(tǒng)基于定價(jià)策略的考慮,會(huì)限制團(tuán)隊(duì)人數(shù)及同時(shí)在線數(shù),如何實(shí)現(xiàn)?
?
通過(guò)?redis?的?zset?可實(shí)現(xiàn)并發(fā)用戶數(shù)。
當(dāng)一個(gè)用戶請(qǐng)求任何接口時(shí),實(shí)現(xiàn)一個(gè) middleware,處理以下邏輯
//?當(dāng)一個(gè)用戶訪問(wèn)任何接口時(shí),對(duì)該用戶Id,寫(xiě)入?zset
await?redis.zadd(`Organization:${organizationId}:concurrent`,?Date.now(),?`User:${userId}`)
//?查詢當(dāng)前機(jī)構(gòu)的并發(fā)數(shù)
//?通過(guò)查詢一分鐘內(nèi)的活躍用戶來(lái)確認(rèn)并發(fā)數(shù),如果超過(guò)則拋出特定異常
const?activeUsers?=?await?redis.zrangebyscore(`Organization:${organizationId}:concurrent`,?Date.now()?-?1000?*?60,?Date.now())
//?查出并發(fā)數(shù)
const?count?=?activeUsers.length
//?刪掉過(guò)期的用戶
await?redis.zrembyscore(`Organization:${organizationId}:concurrent`,?Date.now()?-?1000?*?60,?Date.now())
總結(jié)
每當(dāng)用戶訪問(wèn)服務(wù)時(shí),把該用戶的 ID 寫(xiě)入優(yōu)先級(jí)隊(duì)列,權(quán)重為當(dāng)前時(shí)間 根據(jù)權(quán)重(即時(shí)間)計(jì)算一分鐘內(nèi)該機(jī)構(gòu)的用戶數(shù) 刪掉一分鐘以上過(guò)期的用戶
13 如何把 json 數(shù)據(jù)轉(zhuǎn)化為 demo.json 并下載文件
?在 Issue 中交流與討論: 13 如何把 json 數(shù)據(jù)轉(zhuǎn)化為 demo.json 并下載文件[22]
?
json 視為字符串,可以利用?DataURL?進(jìn)行下載
Text -> DataURL
除了使用 DataURL,還可以轉(zhuǎn)化為 Object URL 進(jìn)行下載
Text -> Blob -> Object URL
可以把以下代碼直接粘貼到控制臺(tái)下載文件
function?download?(url,?name)?{
??const?a?=?document.createElement('a')
??a.download?=?name
??a.rel?=?'noopener'
??a.href?=?url
??//?觸發(fā)模擬點(diǎn)擊
??a.dispatchEvent(new?MouseEvent('click'))
??//?或者?a.click()
}
const?json?=?{
??a:?3,
??b:?4,
??c:?5
}
const?str?=?JSON.stringify(json,?null,?2)
//?方案一:Text -> DataURL
const?dataUrl?=?`data:,${str}`
download(dataUrl,?'demo.json')
//?方案二:Text -> Blob -> ObjectURL
const?url?=?URL.createObjectURL(new?Blob(str.split('')))
download(url,?'demo1.json')
總結(jié)
模擬下載,可以通過(guò)新建一個(gè)? ?標(biāo)簽并設(shè)置?url?及?download?屬性來(lái)下載可以通過(guò)把? json?轉(zhuǎn)化為?dataurl?來(lái)構(gòu)造 URL可以通過(guò)把? json?轉(zhuǎn)換為?Blob?再轉(zhuǎn)化為?ObjectURL?來(lái)構(gòu)造 URL
14 在瀏覽器中如何監(jiān)聽(tīng)剪切板中內(nèi)容
?在 Issue 中交流與討論: 14 在瀏覽器中如何監(jiān)聽(tīng)剪切板中內(nèi)容[23]
?
通過(guò)?Clipboard API?可以獲取剪切板中內(nèi)容,但需要獲取到?clipboard-read?的權(quán)限,以下是關(guān)于讀取剪貼板內(nèi)容的代碼:
//?是否能夠有讀取剪貼板的權(quán)限
//?result.state?==?"granted"?||?result.state?==?"prompt"
const?result?=?await?navigator.permissions.query({?name:?"clipboard-read"?})
//?獲取剪貼板內(nèi)容
const?text?=?await?navigator.clipboard.readText()
?注: 該方法在?
?devtools?中不生效
01 什么是防抖和節(jié)流,他們的應(yīng)用場(chǎng)景有哪些:?https://github.com/shfshanyue/Daily-Question/issues/3
[2]02 在前端開(kāi)發(fā)中,如何獲取瀏覽器的唯一標(biāo)識(shí):?https://github.com/shfshanyue/Daily-Question/issues/28
[3]fingerprintjs2:?https://github.com/Valve/fingerprintjs2
[4]browser independent component:?https://github.com/Valve/fingerprintjs2/wiki/Browser-independent-components
[5]stable component:?https://github.com/Valve/fingerprintjs2/wiki/Stable-components
[6]fingerprintjs2:?https://github.com/Valve/fingerprintjs2
[7]03 在服務(wù)端應(yīng)用中如何獲得客戶端 IP:?https://github.com/shfshanyue/Daily-Question/issues/288
[8]X-Forwarded-For:?https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For
[9]04 js 如何全部替代一個(gè)子串為另一個(gè)子串:?https://github.com/shfshanyue/Daily-Question/issues/361
[10]String.prototype.replaceAll:?https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll
[11]05 如何獲取一個(gè)進(jìn)程的內(nèi)存并監(jiān)控:?https://github.com/shfshanyue/Daily-Question/issues/4
[12]linux 各項(xiàng)監(jiān)控指標(biāo)小記:?https://shanyue.tech/op/linux-monitor.html
[13]06 CORS 如果需要指定多個(gè)域名怎么辦:?https://github.com/shfshanyue/Daily-Question/issues/364
[14]如何避免 CDN 為 PC 端緩存移動(dòng)端頁(yè)面:?https://github.com/shfshanyue/Daily-Question/issues/330
[15]07 既然 cors 配置可以做跨域控制,那可以防止 CSRF 攻擊嗎 :?https://github.com/shfshanyue/Daily-Question/issues/366
[16]08 如何避免 CDN 為 PC 端緩存移動(dòng)端頁(yè)面:?https://github.com/shfshanyue/Daily-Question/issues/330
[17]09 如何實(shí)現(xiàn)表格單雙行條紋樣式:?https://github.com/shfshanyue/Daily-Question/issues/309
[18]10 簡(jiǎn)述下 css specificity:?https://github.com/shfshanyue/Daily-Question/issues/311
[19]:not?的優(yōu)先級(jí)影響 - codepen:?https://codepen.io/shanyue/pen/dyGQqBe
11 node 中 module.exports 與 exports 有什么區(qū)別:?https://github.com/shfshanyue/Daily-Question/issues/351
[21]12 如何獲取當(dāng)前系統(tǒng)中的在線用戶數(shù) (并發(fā)用戶數(shù)):?https://github.com/shfshanyue/Daily-Question/issues/368
[22]13 如何把 json 數(shù)據(jù)轉(zhuǎn)化為 demo.json 并下載文件:?https://github.com/shfshanyue/Daily-Question/issues/352
[23]14 在瀏覽器中如何監(jiān)聽(tīng)剪切板中內(nèi)容:?https://github.com/shfshanyue/Daily-Question/issues/315
[24]【Q019】如何實(shí)現(xiàn)選中復(fù)制的功能:?https://github.com/shfshanyue/Daily-Question/issues/20
