序號
|
|
|
|
1
|
|
Node.js的框架有哪些
|
express koa2
|
2
|
2
|
call 和 apply的區別
|
call 從第二個參數開始逐個傳參
apply 第二個參數是一個數組
|
3
|
4
|
addEventListener最後一個參數
|
true表示捕獲,false表示冒泡
|
4
|
|
狀態碼200什麼意思
|
通信成功
|
5
|
|
狀態碼404
|
客戶端請求錯誤,沒有目標網頁
|
6
|
|
狀態碼500
|
服務器內部錯誤
|
7
|
|
狀態碼503
|
服務器暫時沒法使用
|
8
|
3
|
簡單說幾個性能優化的方法
|
拆分請求
壓縮js html
壓縮合並圖片 走cdn
|
9
|
|
在團隊裏的角色
|
一個應用的小組長
|
10
|
|
錯誤收集方法
|
1 window.onerror
2 邏輯錯誤的地方主動打點收集
3 若有復現步驟,用fiddler把線上js 映射到本地
|
11
|
|
個人經驗
|
1年QA
5年Flash
2年前端
2年egret
|
12
|
|
有哪些緩存
|
cookie 在客戶端和服務端傳遞 最大傳4k 在同源的瀏覽器窗口cookie過時時間以前保存
sessionStorage 瀏覽器關閉那失效
localStorage 永遠存在
|
13
|
2
|
get 和 post 的區別
|
get的參數會存到瀏覽器的歷史中,用於獲取數據,無反作用,冪等
post有反作用,冪不等
get 用於獲取數據 無反作用 固然冪等
delete 用於刪除數據 有反作用 屢次調用效果相同 因此冪等
post 用於提交數據 有反作用 屢次調用產生多條數據 因此冪不等
put 用於提交數據 有反作用 屢次調用只生產或更新一條數據 因此冪等
|
14
|
|
什麼是同域
|
協議 域名 端口 都相同
url = protocol + hostname + port + search + hash
host = hostname + port
origin = protocol + hostname + port
另外還有
href是所有
pathname 問號後斜槓那部分
|
15
|
2
|
Cors 跨源資源共享
|
cross origin resources sharing 跨域資源共享
若帶cookie服務端也要設置
response.setHeader('Access-Control-Allow-Origin',"*");
1 cors須要客戶端和服務端同時支持
2 若是瀏覽器發現ajax請求跨域,就會自動添加一些頭信息,有時還會多發一個請求
3 cors請求有兩類。簡單請求和非簡單請求
簡單請求:類型是head get post, Content-Type只限於下面三個值 application/x-www-form-urlencoded、multipart/form-data、text/plain
4 發送cors簡單請求時,瀏覽器會帶上origin,服務器根據這個值來判斷是否接受請求
4.1 若是沒贊成,會返回200http迴應,但頭信息上沒有帶上Access-Control-Allow-Origin,同時XMLHttpRequest的onerror會被調用
4.2 若是贊成了,返回的http迴應裏,頭信息上會帶有
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true 表示容許帶上cookie 一塊兒發給服務器
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset = utf-8
若是想帶着cookie, 須要作兩步
1 服務器端要設置 Access-Control-Allow-Credentials: true
2 xhr.withCredentials = true
5發送非簡單請求時 會在正式請求前 加一次http查詢請求 即options請求
除了Origin字段,"預檢"請求的頭信息包括兩個特殊字段。
(1)Access-Control-Request-Method
該字段是必須的,用來列出瀏覽器的CORS請求會用到哪些HTTP方法,上例是PUT。
(2)Access-Control-Request-Headers
該字段是一個逗號分隔的字符串,指定瀏覽器CORS請求會額外發送的頭信息字段,上例是X-Custom-Header。
5.1 服務器若是贊成了這個option請求
5.2 正常的請求返回的頭信息將會是這兩個:
Access-Control-Allow-Origin: http://api.bob.com
Content-Type: text/html; charset=utf-8
|
|
2
|
OSI七層
|
Open System Interconnection
物理層 比特流
數據鏈路層 提供介質 鏈路管理
網絡層 尋址 和 路由選擇
傳輸層 創建主機端到端國鏈接
會話層 管理會話
表示層 處理數據格式,數據加密
應用層 提供應用程序間通訊
|
17
|
|
tcp udp 屬於哪一個層
|
傳輸層
|
18
|
|
http 屬於哪一個層
|
傳輸層 |
19
|
|
經常使用排序方法
|
冒泡排序:
let test:number[] = [1,1]
let len:number = test.length
for( let i:number = 0 ; i < len ; i ++ ){
for( let j:number = 0 ; j < len - 1 - i ; j ++ ){
let temp:number = test[j+1];
test[j+1] = test[ j ];
test[j] = temp ;
}
}
時間複雜度 最差狀況O(n2) 最好狀況O(n)
插入排序:
for( let i:number = 1 ; i < len ; i++ ){
for( let j:number = 0 ; j < i ; j ++ ){
if( test[j] > test[i] ){
let a:number = test[i];
test[i] = test[j] ;
test[j] = a ;
}
}
}
|
20
|
3
|
webpack縮小打包體積的方法
四種方法
|
1 第三方庫單獨引用
2 單獨打包css
3 不一樣環境用不一樣一配置文件,以去掉沒必要要的插件
4 選擇合適的devtool, 以優化sourceMap
|
21
|
2
|
請求url到html展現的過程
七步
|
dns 解析
tcp 三次握手
瀏覽器設置好請求報文後發出http請求
服務器處理請求並返回http報文
瀏覽器解析渲染頁面
a html解析器構建dom tree
b css 解析器構建 style rule
a和b共同構造出呈現樹 render tree -> 佈局階段
|
22
|
2
|
html裏的async和defer區別
|
async是下載完就執行
defer是渲染完再執行
|
23
|
2
|
如何減小內存泄露 |
監聽用完要移除
離開場景 清除動畫 中止setTimeout
|
24
|
1
|
有幾個原始類型,它們有方法嗎
|
null undefined boolean number string symbol
原始類型是沒有方法的
|
25
|
|
原始類型 和 對象類型 有什麼區別
|
原始類型 存儲的是值
對象類型 存儲的是地址
|
27
|
|
eval
|
可把字符串解析成js代碼並運行 應避免使用eval 很耗性能
|
28
|
1
|
null和undefined有什麼區別
|
null表示定義了,但值爲空值
undefinded表示不存在這個值
|
29
|
|
typeof 1
typeof '1'
typeof undefined
typeof true
typeof Symbol
typeof 函數
typeof 任何對象類型
|
number
string
undefined
boolean
symbol
function
object
|
30
|
2
|
this 三種狀況
|
直接調用foo,那this必定是window , 必定嗎?
obj.foo(), 誰調用了函數,誰就是this
對於new的方式說, this被永遠綁定在實例上面
箭頭函數的this取決於第一個普通函數的this
|
31
|
2
|
什麼是閉包
|
函數A內部有一個函數B,
函數B能夠訪問到函數A中的變量,
那麼函數B就是閉包
|
32
|
2
|
經典閉包題答案
有三個,只需答兩個
|
方法一
for( var i = 0 ; i <= 5 ; i ++ ){
(function(j){
setTimeout( function timer() {
console.log(j);
}, j * 1000 ) ;
}
})( i ) ;
方法二
setTimeout() 的第三個參數傳 i
方法三
用 let 來定義 i
for( let i = 0 ; i <= 5 ; i ++ ){
setTimeout( function timer(){
console.log( i );
}, i * 1000 );
}
|
33
|
1
|
如何實現淺拷貝
|
let b=Object.assign( {}, a ) ;
let b = { ... a } ;
|
34
|
1
|
如何實現深拷貝
|
JSON.parse( JSON.stringify( a ) ) ; 不支持 undefined Symbol 和 循環引用的對象
方法二:用MessageChannel
|
35
|
2
|
async 和 await 的使用方法
|
async function foo(){
return 1
}
函數前面的async一詞意味着這個函數老是返回一個promise,若是代碼中有return <非promise>語句 以
則會自動把返回的這個value值包裝成promise的resolved的值
即foo().then( 這裏可取到 value 的值 )
|
36
|
2
|
原型和原型鏈
|
每一個實例對象都有一個__proto__指向它的原型對象
這個原型對象的constructor的prototype也指向這個原型對象
對象的 __proto__ 指向原型,對象和原型鏈接起來就組成了原型鏈
Object是全部對象的爸爸,全部對象均可以經過 __proto__ 找到它
Function是全部函數的爸爸,全部函數均可以經過 __proto__ 找到它
函數的 prototype 是一個對象
|
37
|
2
|
什麼是變量提高
|
1 函數提高優先於變量提高,函數提高會把整個函數挪到做用域頂部,變量提高只會把聲明挪到做用域頂部
2 let const 不能提高,在window上找不到
|
38
|
1
|
class
|
語法糖 本質仍是函數
|
39
|
2
|
繼承類型
|
組合繼承
寄生組合繼承
|
40
|
2
|
爲何要使得模塊化
|
解決命名衝突
提升複用性
提升代碼的可維護性
|
41
|
1
|
es6模塊化
|
1 es6模塊不是對象
es6是編譯時加載或者叫靜態加載,即在編譯時完成模塊加載
export變量有兩種方法
export var name:string = a; 或者
var name:string = 'a';
export {name } ; (我習慣用第一種,但書上建議用第二種)
export { name as test } 能夠重命名 但不建議
import
若是模塊名不含路徑,那麼import命令會去 node_modules 目錄尋找這個模塊
引入變量
import { first as test } from '路徑'
import 都是在編譯時加載的,不能在運行時加載
也能夠總體加載
import { * as circle } from '路徑'
關於default
export default XXX
import YYY from "" // 這樣引入的YYY表明的就是XXX
require是運行時加載模塊
|
42
|
|
proxy
|
Vue3.0中將會經過Proxy來替換本來的Object.defineProperty 來
實現數據響應式
|
43
|
1
|
map
filter
reduce
forEach
|
生成一個新數組
過濾生成一個新數組
const sum = arr.reduce( (acc, current) => acc + current, 0 ) ;
對每一項來執行
|
44
|
2
|
併發和並行concurrency
|
併發是宏觀概念,我分別有任務A和任務B,在一段時間內經過任務間的切換完成了這兩個任務
並行是微觀概念,假設cpu存在兩個核心 那麼我就能夠同時完成任務A和B
|
45
|
1
|
回調函數的缺點
|
改變牽一髮而動全身
不能return
不能用try catch
|
46
|
2
|
generator函數返回什麼
|
generator函數是一個狀態機,封閉了內部狀態。
執行generator會返回一個遍歷器對象,
var hw = helloWorldGenerator() // hw是一個指向內部狀態的指針對象
|
|
2
|
generator有哪兩個特徵
|
function後有一個*
內部使用yield表達式
|
|
2
|
Promise的本質
|
Promise的寫法只是回調函數的改進,只能讓異步任務看得更清楚,另外多了一個總體catch錯誤的方法
|
47
|
3
|
異步編程方法有哪些
|
回調函數
事件監聽
發佈訂閱
Promise
|
48
|
2
|
js是什麼線程
|
一個進程包括不少線程,線程只能逐個執行
js是單線程執行的
|
49
|
2
|
什麼是執行棧
|
遵循先進後出的原則 |
50
|
2
|
異步代碼執行順序是什麼 |
Event Loop
先執行微任務 再執行宏任務
微任務: process.nextTick() promise MutationObserver
宏任務有: script setTimeout setInterval setImmdiate I/O UI
rendering
|
51
|
2
|
V8下的垃圾回收機制
|
新生代算法:新分配的對象會被放入From空間中,
當From空間被佔滿時,GC 就會啓動,
、檢查From空間中存活的對象並複製到To空間中,若是有失活的對象就會銷燬。當複製完成後將From和To空間互換
|
52
|
2
|
開發者工具裏的技巧
|
Element裏右鍵選擇 scroll into view
Edit Break,在for循環裏當i是某值時,就停在斷點
|
53
|
2
|
事件觸發過程
|
window -> 捕獲 -> 目標 -> 冒泡 -> window
|
55
|
3
|
stopPropagation
|
來用阻止事件的進一步傳播,能夠阻止事件冒泡和捕獲
|
56
|
2
|
stopImdiatePropagation
|
stopPropagation + 阻止該事件目標執行別的註冊事件
|
57
|
2
|
什麼是事件代理
|
即子節點須要註冊事件的話,就註冊到父節點上
|
58
|
3
|
跨域是爲了防什麼
|
用來防止csrf攻擊,即利用用戶的登陸態發起惡意請求,瀏覽器攔截了這個響應
|
59
|
2
|
解決跨域問題的方法
|
方法一 jsonp
jsonp
function jsonp(url, jsonpCallback, success) {
let script = document.createElement('script')
script.src = url
script.async = true
script.type = 'text/javascript'
window[jsonpCallback] = function(data) { success && success(data)
}
document.body.appendChild(script);
}
jsonp('http://xxx', 'callback', function(value) {
console.log(value)
})
方法二 Cors cross origin resources sharing
須要目標服務器的後端response.setHeader 把 Access-Control-Allow-Origin 設置爲 * 或容許www.test.17zuoye.net的加載
要找專門的cdn服務端 好比bootCDN
// 接收跨域的cookie response.setHeader("Access-Control-Allow-Credentials", "true");
|
60
|
|
實現儲存有哪些方法
|
cookie sessionStorage localStorage indexDB
|
61
|
2
|
cookie的屬性
|
cookie.http-only 不能經過js來訪問,以減小xss攻擊
cookie.secure 只能在https中攜帶
cookie.same-site 不能在跨域請求中攜帶
|
62
|
|
瀏覽器的緩存有哪引發位置 |
Service Worker
Memory Cache
Disk Cache
Push Cache
網絡請求
|
63
|
3
|
兩種緩存策略
|
強緩存 協商緩存
|
64
|
2
|
firefox ui引擎
|
Gecko
|
65
|
2
|
chrome 和 safari 裏的 ui 引擎
|
Webkit
|
66
|
4
|
html渲染過程
|
瀏覽器接收到字節數據 -> 字符串 -> token -> Node 鏈接成Dom樹
|
67
|
4
|
css渲染過程
|
字節數據 -> 字符串 -> Token -> Node -> 鏈接成CSSOM樹
過於具體的css選擇器,因要經過遞歸尋找,因此很是消耗資源
|
68
|
1
|
DOM樹 CSSOM樹
|
兩個一志渲染樹 -> reflow painting -> 調用gpu繪製 合成圖層
|
69
|
3
|
若是實現插入不少Dom頁面不卡頓
|
方法一:requestAnimationFrame 循環插入Dom
方法二:虛擬滾動 visualized scroller,即用react-visualized
|
70
|
3
|
如何減小阻塞渲染
|
1 減小html層級,減小css的複雜度
2 defer: script放到body最後,或者給script標籤增長defer屬性,表示js文件或並行下載,htmll解決完順序執行
3 async: 對於沒有任何依賴的js文件能夠加async屬性,表示js下載和解析不會阻塞渲染
|
71
|
2
|
重繪 repaint
迴流 reflow
|
重繪:改外觀而不改佈局,好比改變顏色
迴流:改變佈局
|
72
|
3
|
減小重繪和迴流 5 個
|
使用transform代替top
使用visibility替代display:none
少用js改變dom
動畫速度越多,迴流次數越多
頻繁變化的節點要設置爲圖層,這樣不會影響別的節點
|
73
|
3
|
XSS攻擊 如何防範
|
cross site scripting 插入可執行的代碼
1 永遠不信任用戶的輸入
2 創建 CSP Content-Security-Policy 白名單,能夠http header裏設置,也可在meta裏
2.1 只容許加載本站資源 default-src: 'self'
2.2 只容許加載https協議圖片 img-src: https://*
2.3 容許加載任何來源的 child-src:'none'
|
74
|
3
|
CSRF攻擊 如何防範4種
|
cross site request forgery 跨站僞造請求(僞造前端請求向後端發請求)
1 用get請求不對數據進行修改
2 設置cookie.same-site 不讓第三方網站訪問到用戶的 cookie
3 阻止第三方網站請求接口(驗證referer來判斷請求是否爲第三方發起的)
4 請求時要帶驗證信息,好比驗證碼或Token
|
75
|
3
|
點擊劫持 如何防範
|
將要攻擊的網站放到iFrame裏面,僞造入口讓用戶點擊
方法一 X-Frame-Options
deny:表示頁面不容許經過iframe的方式展現
sameorigin:表示頁面只能夠在相同域名下經過iframe的方式展現
allow from表示頁面能夠在指定來源的iframe中展現
方法二:js防護
if (self == top) { var style = document.getElementById('click-jack') document.body.removeChild(style) } else { top.location = self.location }
|
76
|
2
|
中間人攻擊 防範
|
中間人和客戶端和服務端都創建了鏈接
解決方法:用https,而且關閉對http的修改訪問。
|
77
|
2
|
測試性能工具
|
Audits 和 Performance
|
78
|
2
|
v8 JS性能優化
|
js -》抽象語法樹 -> 用ignition轉成ByteCode -> 用compiler turboFan 轉成Machine code
讓代碼儘量多的轉爲機器容易讀的machine code
就應該讓類型強制
v8引擎能把性能提高20多倍
|
79
|
2
|
圖片優化方法 |
用css 不用圖片
移動端,最好請求裁好的圖片
多個圖片合併成一張圖
大圖用webP, 小圖用png,圖標用svg,照片用jpeg
|
80
|
1
|
DNS預解析
|
預解析出ip地址
|
81
|
1
|
節流方法
|
不但願滾動過程當中一直髮出請求,可用throttle來實現
即實現一個執行間隔,不斷執行
下拉加載新內容
|
82
|
1
|
防抖方法
|
debounce 用於下拉條,在事件派發過來中,只執行一次行爲
debounce分爲前緣和後緣
|
83
|
|
預加載
|
<link rel='preload' />
|
84
|
|
預渲染
|
<link rel='prerender' href='http://example.com'/>
|
85
|
1
|
懶加載 |
即將不關鍵的資源延後加載
懶加載圖片 js 視頻
|
86
|
1
|
cdn
|
content delivery network 內容分發網絡
即把靜態資源放到不一樣服務器上
|
87
|
1
|
webpack打包速度和打包大小
|
1 優化Loader的文件搜索範圍
{ // js 文件才使用 babel
test: /\.js$/,
loader: 'babel-loader', // 只在 src 文件夾下查找
include: [resolve('src')],
// 不會去查找的路徑 exclude: /node_modules/ }
2 緩存Babel編譯過的文件
loader: 'babel-loader?cacheDirectory=true'
3 HappyPack
Node是單線程的,因此Webpack也是單線程,特別是在執行Loader的時候,長時間編譯的
任務不少,這樣就會致使等待的狀況。
HappyPack能夠把Loader的同步執行轉換爲並行的
這樣寫:loader:'happpack/loader?id=happybabel'
plugins:[
new HappyPack(
id:'happybabel',
loaders:[ 'babel-loader?cacheDirectory'],
threads: 4 ,
)
]
4 DllPlugin 能夠將特定的類庫提早打包而後引入
這極大地減小打包類庫的次數,只有當類庫更新版本纔有須要從新打包,而且
也實現了將公共代碼抽離成單獨文件的優化方案。
具體略
5 代碼壓縮
在 webpack4中,把mode設置爲production時,就會並行壓縮js代碼了
resolve.extensions
resolve.alias
module.noParse
6 按需加載,底層原理都是Promise
7 Scope Hoisting
代碼就會盡量把打包出來的模塊合併到一個函數中去
module.exports = {
optimization: { concatenateModules: true }
}
8 Tree Shaking
實現刪除項目中未被引用的代碼
webpack4中,mode設置爲production,就會自動刪去
|
88
|
3
|
MVVM的精髓是什麼
|
經過ViewModel將視圖中的狀態和用戶的行爲分離出一個抽象
View Binder ViewModel Model
|
89
|
1
|
visual Dom
|
Virtual DOM 實際上沒有使用什麼全新的技術,僅僅是把 「 雙緩衝(double buffering)」 技術應用到了DOM上面。
這樣一來,當你在這個單獨的虛擬的DOM樹上也一個接一個地修改30個節點的時候,它不會每次都去觸發重繪,因此修改節點的開銷就變小了。
以後,一旦你要把這些改動傳遞給真實DOM,以前全部的改動就會整合成一次DOM操做。這一次DOM操做引發的佈局計算和重繪可能會更大,可是相比而言,整合起來的改動只作一次,減小了(屢次)計算
|
90
|
3
|
路由實現方式
|
Hash History 模式
|
91
|
2
|
vue v-show v-if
|
|
92
|
2
|
響應式原理 |
Object.defineProperty() 來實現數據響應式
經過這個函數能夠監聽到set和get事件
|
93
|
|
Vue編譯過程是什麼
|
模板 -> AST -> render函數 -> virtual Dom --> 真實的dom
|
94
|
|
nextTick原理分析
|
可以讓咱們在下次dom更新循環結束後執行延遲迴調,用於得到更新後的Dom
setImmediate -> MessageChannel -> setTimeout
|
95
|
|
React - Fiber |
它是一個虛擬的堆棧幀,
|
96
|
2
|
UDP
|
不須要創建鏈接,不須要驗證數據報文,不須要流量控制,
但它可在實時性要求高的地方有所做爲。好比視頻和遊戲
|
97
|
2
|
TCP
|
創建鏈接或斷開鏈接都須要先握手
在傳輸數據的過程當中,經過各類算法來保證數據的可靠性
|
98
|
|
TCP的頭部信息
|
sequence number 可保證傳輸的報文都是有序的
acknowlegement number 這個序號表示數據接收端指望接收的下
|
99
|
1
|
TCP如何鏈接
|
創建鏈接要三次握手
客戶端向服務端發
服務端應答
客戶端確認
斷開鏈接要4次握手
|
100
|
|
HTTP協議三部分
|
請求行 首部 實體
請求行:請求方法 url 協議版本
|
101
|
|
頭部有哪四種
|
用戶首部 請求首部 響應首部 實體首部
|
102
|
|
get post區別
|
get 無反作用 且冪等
post 有反作用 不冪等
|
103
|
|
TLS 技術
|
https經過http來傳輸信息,可是信息經過tls協議進行了加密
有兩種加載技術:對稱加密 + 非對稱加密
對稱加密 即兩邊有相同的密鑰
非對稱加密
|
104
|
|
狀態碼的規律
|
2xx 成功
3xx 重定向
4xx 客戶端錯誤
5xx 服務端錯誤
|
|
|
時間複雜度
|
O(N)
|
|
|
棧 |
先進後出 push pop shifit unshift
|
|
|
隊列
|
先進先出
|
|
|
鏈表 |
|
|
|
二叉樹
|
|
|
|
二分搜索數
|
|
|
|
AVL樹
|
|
|
|
Trie
|
|
|
|
並查集
|
|
|
|
堆
|
|
|
|
MVVM的精髓
|
viewModel將視圖中的狀態和用戶的行爲分離出一個抽象
|
|
|
Virtual DOM
|
React團隊優化了算法,實現了O(n)的複雜並來對比差別,只對比同層的節點,而不是跨層對比,這也是考慮到在實際業務中不多會跨層的移動Dom元素
|
|
|
路由原理
|
本質就是監聽url的變化 有兩種實現方式:Hash模式 History模式
|
|
|
Vue和React的區別
|
Vue的表單可以使用v-model支持雙向綁定
Vue上手成本更低
|
|
|
Vue有哪些鉤子函數
|
beforeCreate
created
beforeMount
beforeUpdate
updated
activated
deactivated
beforeDestroy
destroyed
|
|
|
父子通信方法
|
父組件經過props傳遞數據給子組件
子組件emit事件給父組件
經過訪問@parent和$children來訪問對方
$listener屬性會將父組件中的v-on事件監聽器傳遞給子組件
子組件經過訪問$listenerso來自定義監聽器
.sync
|
|
|
兄弟組件經過
|
this.$parent.$children 再查找name來實現
|
|
|
跨多層次組件通訊
|
provide
inject
|
|
|
任意組件 | Vuex 或 Event Bus 解決 |
|
|
mixin和
mixins的區別
|
mixin用於全局混入,會影響到每一個組件實例,一般插件都是這樣初始化的
mixins是咱們最多見的擴展組件的方式
|
|
|
computed和watch的區別
|
computed 只有當計算值變化纔會返回內容
watch 監聽到值的變化就會執行回調
vm.$watch()
|
|
|
v-show v-if
|
v-if 表示不渲染
|
|
|
哪些事件不支持冒泡
|
ui事件 load unload 鼠標事件 mouseleave 焦點事件 blur focus
|
|
|
|
|
什麼是函數柯里化
|
add()()
|
es6的方法實現數組去重
|
let array = [1, 1, 1, 1, 2, 3, 4, 4, 5, 3];
let set = new Set(array); let arr = Array.from(set);
|
css中的層疊
|