面試真題

var和let const的區別
  • var是ES5語法,let const是ES6語法;var有提高變量
  • var和let是變量可修改;const是常量,不可修改
  • let const有塊級做用域,var沒有
    • *
typeof返回哪些類型
  • undefined
  • string
  • number
  • boolean
  • symbol
  • object(typeof null === 'object')
  • function
    • *
列舉強制類型轉換和隱式類型轉換

強制:parseInt parseFloat toString
隱式:if、邏輯運算、==、+拼接字符串css


手寫深度比較isEqualnode

//判斷是不是對象或者是數組
function isObject(obj){
    return typeof obj === 'object' && obj !== null
}
function isEqual(obj1,obj2){
    if(!isObject(obj1) || !isObject(obj2)){
        //值類型
        return obj1 === obj2
    }
    if(obj1 === obj2){
        return true
    }
    //兩個都是數組或者對象
    //一、先取出obj1和obj2的keys,比較個數
    const obj1Keys = Object.keys(obj1)
    const obj2Keys = Object.keys(obj2)
    if(obj1Keys.length !== obj2Keys.length){
        return false
    }
    //二、以obj1爲基準,和obj2遞歸依次比較
    for(let key in obj1){
        //比較當前key的value值
        const res = isEqual(obj1[key],obj2[key])
        if(!res){
            return false
        }
    }
    return true
}
const obj1 = {
    a:100,
    b:{
        x:100,
        y:200
    }
}
const obj2 = {
    a:100,
    b:{
        x:100,
        y:200
    }
}

split()和join()的區別ajax

'1-2-3'.split('-')  //[1,2,3]
[1,2,3].join('-')   //'1-2-3'

數組的pop push unshift shift分別是什麼
  • pop 在末尾刪除一個值,返回的是數組最後的一個值
const arr = [10,20,30,40]
const popRes = arr.pop()
console.log(popRes) //40
console.log(arr)  //[10,20,30]
  • push 在數組末尾插入一個數值,返回的是數組的長度
const arr = [10,20,30,40]
const pushRes = arr.push(50)
console.log(pushRes) // 5
console.log(arr)  //[10,20,30,40,50]
  • unshift 在數組第一位插入一個值,返回的是數組的長度
const arr = [10,20,30,40]
const unshiftRes = arr.unshift(5)
console.log(unshiftRes) // 5
console.log(arr)  //[5,10,20,30,40]
  • shift 刪除數組第一個值,返回的是數組的被刪除的值
const arr = [10,20,30,40]
const shiftRes = arr.shift(5)
console.log(shiftRes) // 10
console.log(arr)  //[20,30,40]

image.png


純函數
一、不改變原數組(沒有反作用)
二、返回的是一個數組
concat
const arr = [10,20,30,40]
const arr1 = arr.concat([50,60,70])
console.log(arr)  //[10,20,30,40]
console.log(arr1) //[10,20,30,40,50,60,70]
map
const arr = [10,20,30,40]
const arr2 = arr.map(num=>num*10)
console.log(arr)  //[10,20,30,40]
console.log(arr2) //[100,200,300,400]
filter
const arr = [10,20,30,40]
const arr3 = arr.filter(num=>num>25)
console.log(arr)  //[10,20,30,40]
console.log(arr3) //[30,40]
slice
const arr = [10,20,30,40]
const arr4 = arr.slice()
console.log(arr)  //[10,20,30,40]
console.log(arr4) //[10,20,30,40]

slice和splice的區別
slice純函數
const arr = [10,20,30,40,50]
const arr1 = arr.slice(1,4) //第一個參數爲從第幾個位置開始,第二個參數爲到第幾個位置前結束
const arr2 = arr.slice(2)
const arr3 = arr.slice(-2) //截取最後兩位
console.log(arr1) //[20,30,40]
console.log(arr2) //[30,40,50]
console.log(arr3) //[40,50]
splice非純函數
const arr = [10,20,30,40,50]
const spliceRes = arr.splice(1,2,'a','b','c')//參數含義:把第一個參數到第二個參數位置剪切下來,把後面的參數放在剪切區域內
console.log(arr)  //[10,'a','b','c',40,50]
console.log(spliceRes) //[20,30]

[10,20,30].map(parseInt)
const res = [10,20,30].map(parseInt)
console.log(res) //[10,NaN,NaN]
//拆解
[10,20,30].map((num,index) = >{
    return parseInt(num,index)
})

ajax請求get和post的區別
  • get在瀏覽器回退是無害的,而post則會再次提交請求
  • get產生的url地址能夠被收藏,而post不能夠
  • get請求會被瀏覽器主動緩存,而post不會,除非手動設置
  • get請求只能進行url編碼,而post支持多種編碼方式
  • get請求參數會被完整的保存在瀏覽器歷史記錄裏,而post參數不會被保留
  • get請求在url中傳送參數是有長度限制的,而post沒有限制
  • 對參數的數據類型,get只接受ASCLL字符,而post沒有限制
  • get比post更不安全,由於參數直接暴漏在url上,不能傳遞敏感信息
  • get參數經過url傳遞,post放在request body中
    • *
JavaScript中 call和apply
apply()方法 接收兩個參數,一個是函數運行的做用域(this),另外一個是參數數組。
call()方法 第一個參數和apply()方法的同樣,可是傳遞給函數的參數必須列舉出來。

阻止事件冒泡和默認行爲

event.stopPropagation()
event.preventDefault()正則表達式


查找、添加、移動、刪除Dom節點
const div1 = document.getElementById("div1")
//添加新節點
const newP = document.createElement('p')
newP.innerHTML = "this is p1"
div1.appendChild(newP)//添加新建立的元素
//移動已有節點,注意是移動
const p2 = document.getElementById('p2')
div1.appendChild(p2)
//獲取子元素列表
const div1 = document.getElementById("div1")
const div1ChildNodes = div1.childNodes
console.log(div1.childNodes)//打印出兩種標籤,一種是p標籤,一種是text標籤,由於p標籤裏面含有文本,text的nodeType爲3,p的nodeType爲1,因此經過轉化爲數組過濾。
const div1ChildNodesP = Array.prototype.slice.call(div1.childNodes).filter(child=>{
    if(child.nodeType == 1){
        return true
    }
    return false
})
//刪除子節點
div1.removeChild(div1ChildNodesP[0])
//獲取父元素
const div1 = document.getElementById("div1")
const parent = div1.parentNode

如何減小DOM操做
  • 緩存DOM查詢結果
  • 屢次DOM操做,合併到一次插入
    • *
函數聲明和函數表達式的區別

函數聲明function fn(){}
函數表達式const fn = function(){}json


new Object()和Object.create()的區別

{}等同於new Object(),原型鏈Object.prototype
Object.create(null)沒有原型
Object.create({})能夠指定原型數組


常見的正則表達式
字符串字母開頭,後面字母數字下劃線,長度6-30
const res = /^[a-zA-Z]\w{5,29}$/
郵政編碼
const res = /\d{6}/
去除兩端空格
String.prototype.trim = function(){
    return this.replace(/^\s+/,'').replace(/\s+$/,'')
}

獲取多個數字中的最大值
//第一種獲取最大值
Math.max(10,20,30,40) //40
//第二種獲取最大值
function max(){
    const nums = Array.prototype.slice.call(arguments)//變爲數組
  let max = nums.length ? nums[0] : null
  nums.forEach(n=>{
    if(n>max) {
        max = n
    }
  })
  return max
}
//獲取最小值
Math.min(10,20,30,40) //10

捕獲js異常
//第一種手動捕獲異常
try{

}.catch(ex){
    console.error(ex) //手動捕獲異常
}.finally{

}

//第二種自動捕獲異常
window.onerror = function(message,source,lineNum,colNum,error){
    console.log(message,source,lineNum,colNum,error)
}

json
json是一種數據格式,本質是一串字符串
json格式和js對象結構一致,對js語言更友好
window.json是一個全局對象:JSON.stringify JSON.parse

獲取當前頁面url參數

location.search
URLSearchParams瀏覽器

//傳統方式
functoin query1(name){
    const search = location.search.substr(1)//去掉前面的‘?’
    const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`,'i')
    const res = search.match(reg)
    if(res == null){
        return null
    }
    return res[2]
}
//URLSearchParams
funcrion query2(name){
    const search = location.search
    const p = new URLSearchParams(search)
    return p.get(name)
}

//將url參數解析爲json對象
function queryToObj(){
    const res = {}
    const search = location.search.substr(1)
    search.split('&').forEach(paramsStr=>{
        const arr = paramsStr.split('=')
        const key = arr[0]
        const val = arr[1]
        res[key] = val
    })
    return res
}

數組排平[1,2,[3,4,[5]],6] => [1,2,3,4,5,6]
function flat(arr){
    const isDeep = arr.some(item=>item instanceof Array)
    if(!isDeep){
        return arr
    }
    const res = Array.prototype.concat.apply([],arr)
    return flat(res)
}

數組去重
//第一種
function unique(arr){
    const res = []
    arr.forEach(item=>{
        if(res.indexOf(item)<0){
            res.push(item)
        }
    })
    return res
}
//第二種
function unique(arr){
    const set = new Set(arr)
    return [...set]
}

手寫深拷貝

Object.assign爲淺拷貝緩存

function deepClone(obj = {}) {
    if (typeof obj !== 'object' || obj == null) {
        // obj 是 null ,或者不是對象和數組,直接返回
        return obj
    }
 
    // 初始化返回結果
    let result
    if (obj instanceof Array) {
        result = []
    } else {
        result = {}
    }

    for (let key in obj) {
    // 保證 key 不是原型的屬性
        if (obj.hasOwnProperty(key)) {
        // 遞歸調用!!!
            result[key] = deepClone(obj[key])
        }
    }

     // 返回結果
    return result
  }
RAF requestAnimationFrame動畫
更新頻率要60幀/s,即16.67ms跟新一次視圖
//設置一個div寬度爲100px,3s後變爲640px,即增長540px
//60幀/s  3s->180幀 每次變化3px
const $div1 = $("#div1")
let curWidth=100
let maxWidth=640
//第一種
function animate(){
    curWidth =+ curWidth
    $div1.css('width',curWidth)
    if(curWidth<naxWidth){
        setTimeout(animate,16.7)
    }
}
//第二種
function animate(){
    curWidth =+ curWidth
    $div1.css('width',curWidth)
    if(curWidth<naxWidth){
        requestAnimationFrame(animate)
    }
}
animate()
相關文章
相關標籤/搜索