**如何理解原型鏈
每個函數(shù)都擁有一個prototype屬性,每個函數(shù)實例對象都擁有一個proto屬性,而這個屬性指向了函數(shù)的prototype,當(dāng)我們訪問實例對象的屬性或者方法時,會先從自身構(gòu)造函數(shù)中查找,如果沒有就通過proto去原型中查找,這個查找的過程我們稱之為原型鏈。(跟作用域鏈有點像)
// 定義動物 - 父類
function Animal(){
this.age = 10;
this.say = function(){
return 'hello tom';
}
}
// 定義貓 - 子類
function Cat(){
this.name = 'tom';
}
// 通過原型繼承動物類
Cat.prototype = new Animal()
// 實例化一個cat對象
var cat = new Cat();
// 打印返回true
cat.__proto__ === Cat.prototype
// 打印age,會先查找cat,再查找Animal
console.log(cat.age)

通過截圖,我們可以看到cat實例對象proto指向了Animal,當(dāng)cat沒有age的時候,會通過proto到原型上查找,如果原型上依然沒有,會繼續(xù)向Object上查找。
**什么是閉包
簡單理解就是函數(shù)中嵌套函數(shù)。我們都知道局部變量我們是無法訪問的,但是通過閉包可以做到。
// 正常訪問
var lan = 'zh';
function hello(){
var name = '前端未來';
}
console.log(name)//很明顯'undefined'
// 換成閉包
function hello(){
var name = '前端未來';
function demo(){
console.log(name)//打?。呵岸宋磥? }
}
**什么是深/淺拷貝,有哪些實現(xiàn)方式
JS數(shù)據(jù)類型分別基本數(shù)據(jù)類型和引用數(shù)據(jù)類型,基本數(shù)據(jù)類型保存的是值,引用類型保存的是引用地址(this指針)。淺拷貝共用一個引用地址,深拷貝會創(chuàng)建新的內(nèi)存地址。
- 淺拷貝方法
直接對象復(fù)制
Object.assign - 深拷貝
JSON.stringify轉(zhuǎn)為字符串再JSON.parse
深度遞歸遍歷
**如何準(zhǔn)確判斷一個對象是數(shù)組
面試官希望的答案:
- Object.prototype.toString.call([]) 返回 "[object Array]"
擴(kuò)展答案 - [].slice (能力判斷 )
- [] instanceof Array(類型判斷)
- [].proto === Array.prototype
- Array.isArray([]) 存在兼容問題
- 數(shù)組也是引用類型,通過typeof依然返回object
**數(shù)組有哪些常用方法
這個非常多,說起來也很快,我主要考察你會多少,另外也為了引出下一個問題,slice和splice區(qū)別
- push 末尾添加
- pop 末尾刪除
- shift 首部刪除
- unshift 首部添加
- concat 數(shù)組合并
- join 數(shù)組元素 通過連接符 連接
- reverse 數(shù)組反轉(zhuǎn)
- sort 數(shù)組排序
- map/forEach/filter/indexOf/includes/slice/splice
- slice表示截取,slice(start,end)不改變原數(shù)組,返回新數(shù)組。
- splice表示刪除,splice(start,length,item),會改變原數(shù)組,從某個位置開始刪除多個元素,并可以插入新的元素。
**CSS實現(xiàn)三列布局(左右固定寬度,中間自適應(yīng))
- CSS浮動
第一個float:left,第二個float:right,第三個設(shè)置margin-left和margin-right - 絕對定位法
第一個定位到left,第二個定位到right,第三個設(shè)置margin-left和margin-right - flex布局
**H5自適應(yīng)方案
H5自適應(yīng)方案大家在網(wǎng)速能找到很多,我個人推薦一種我非常喜歡的方式,就是rem. rem是一種相對單位,它基于html的font-size值來進(jìn)行調(diào)整。
通常我們以750為基準(zhǔn),我們會在header中嵌套一段js腳本,獲取手機(jī)網(wǎng)頁分辨率尺寸除以375,為了方便計算,我們假設(shè)750像素下1rem = 100px;所以 我們除以375后需要乘以50.
**call/apply/bind作用和區(qū)別
他們都可以改變函數(shù)的作用域。
- call/apply可以直接執(zhí)行該函數(shù),而bind不會立刻執(zhí)行
- call/apply作用類似,都可以改變指針和執(zhí)行函數(shù),區(qū)別在于傳參不同,call需要單個傳參,apply通過數(shù)組傳參
瀏覽器解析渲染頁面過程
- 解析HTML,生成DOM樹
- 解析CSS,生成CSSOM樹
- 將DOM樹和CSSOM樹關(guān)聯(lián),生成渲染樹(Render Tree)
- 布局render樹(Layout/reflow),負(fù)責(zé)各元素尺寸、位置的計算
- 繪制render樹(paint),繪制頁面像素信息
- 將像素發(fā)送給GPU,展示在頁面上。(Display)
**談一下防抖和節(jié)流
防抖和節(jié)流都是希望在同一時間內(nèi),不要重復(fù)觸發(fā)請求。一般場景用在搜索和網(wǎng)頁滾動事件中。
區(qū)別:
- 防抖主要是在規(guī)定時間內(nèi)只觸發(fā)一次,如果再次調(diào)用,時間從新計算。
- 節(jié)流主要是在固定時間內(nèi)只觸發(fā)一次。比如每間隔1秒觸發(fā)一次。
**數(shù)組如何去重
- ES6 Set去重
- 利用Object key去重
- 兩層循環(huán)逐一對比,生成新數(shù)組
- indexOf去重
- sort排序,再單層循環(huán)前后對比
**前端有哪些跨域方案
- JSONP跨域(本質(zhì)是JS調(diào)用)
- CORS(后臺設(shè)置)
- Nginx反向代理(運(yùn)維配置)
- 跨域是瀏覽器做出的安全限制,必須同協(xié)議、同域名、同端口否則會被瀏覽器block
不常用跨域方案,我不進(jìn)行列出
**前端網(wǎng)站常規(guī)優(yōu)化方案
- 優(yōu)化策略:減少請求次數(shù)、減小資源大小、提高響應(yīng)和加載速度、優(yōu)化資源加載時機(jī)、優(yōu)化加載方式
合并、壓縮、混淆html/css/js文件(webpack實現(xiàn),減小資源大?。?/li> - Nginx開啟Gzip,進(jìn)一步壓縮資源(減小資源大?。?/li>
- 圖片資源使用CDN加速(提高加載速度)
- 符合條件的圖標(biāo)做base64處理(減小資源大小)
- 樣式表放首部,JS放尾部(JS單線程,會阻塞頁面;資源加載方式)
- 設(shè)置緩存(強(qiáng)緩存和協(xié)商緩存,提高加載速度)
link或者src添加rel屬性,設(shè)置prefetch或preload可預(yù)加載資源。(加載時機(jī)) - 如果使用了UI組件庫,采用按需加載(減小資源大小)
SPA項目,通過import或者require做路由按需(減小資源大?。?/li> - 服務(wù)端渲染SSR,加快首屏渲染,利于SEO
- 頁面使用骨架屏,提高首頁加載速度(提高加載速度)
- 使用 JPEG 2000, JPEG XR, and WebP 的圖片格式來代替現(xiàn)有的jpeg和png,當(dāng)頁面圖片較多時,這點作用非常明顯
使用圖片懶加載-lazyload