【建議👍】記錄一次BAT一線互聯網公司前端JavaScript面試

前沿

置身世外只爲暗中觀察!!!Hello你們好,我是魔王哪吒!javascript

面試內容

你須要一些HTML和css的基礎知識,掌握JavaScript和ES6的基本語法,對事物的好奇心。css

  • 初級JS面試題
  • JS Web API,開發環境,運行環境
  • 原型,做用域,異步,Ajax,事件,webpack等

觀察全部面試題的考點

  1. 學習梳理知識體系圖
  2. 找準知識體系,刻意掌握
  3. 善於總結觀點,原理

typeof能判斷哪些類型

typeof運算符:html

  • 能夠識別全部值的類型
  • 能夠識別函數
  • 能夠用力判斷是否爲引用類型

考點:JS變量類型前端

代碼:html5

// 判斷全部值的類型
let a; typeof a // 'undefined'
const str = 'abc'; typeof str // 'string'
const n = 10; typeof n // 'number'
const b = true; typeof b // 'boolean'
const s = Symbol('s'); typeof s // 'symbol'

// 可以判斷函數
typeof console.log // 'function'
typeof function(){} // 'function'

// 可以識別引用類型
typeof null // 'object'
typeof ['a','b'] // 'object'
typeof {x:10} // 'object'
複製代碼

何時使用===,何時使用==

考點:強制類型轉換java

字符串拼接的類型轉換node

const a = 10 + 1 // 11
const b = 10 + '10' // '1010'
const c = true + '1' // true1
複製代碼

解決方法:jquery

10 + parseInt('1') // 11
複製代碼

== 運算符的類型轉換linux

100 == '100' // true
0 == '' // true
0 == false // true
false == '' // true
null == undefined // true
複製代碼

類型轉換webpack

  1. 除了0以外的全部數字,轉換爲布爾型都爲true
  2. 除了「 」以外的全部字符,轉換爲布爾型都爲true
  3. nullundefined轉換爲布爾型爲false

何時使用===,何時使用==

除了==null外,其餘地方用===

const obj = {a:1}
if(obj.b==null){}
// 至關於
//if(obj.b === null || obj.b === undefined){}
複製代碼

window.onload和DOMContentLoaded的區別

考點:頁面加載過程

建立10個標籤,點擊後彈出對應的序號

考點:JS做用域

手寫節流 throttle,防抖 debounce

考點:性能,體驗優化

Promise解決了什麼問題

考點:JS異步

值類型和引用類型的區別

值類型的表示:

// 值類型
let a = 10
let b = a
a= 20
console.log(b); // 10
複製代碼

引用類型的表示:

// 引用類型
let a = { age:12 }
let b = a
b.age = 13
console.log(a.age) // 13
複製代碼

手寫深拷貝

  1. 判斷是值類型仍是引用類型
  2. 判斷是數組仍是對象
  3. 遞歸

代碼:

// 淺拷貝
const obj1 = {
    age: 12,
    name: 'web',
    address: {
        city: 'beijing'
    },
}

const obj2 = obj1
obj2.address.city = 'shanghai'
console.log(obj1.address.city)
複製代碼

結果:

shanghai
複製代碼

深拷貝:定義要拷貝的對象

const obj2 = deepClone(obj1)
obj2.address.city = 'shanghai'
console.log(obj1.address.city)

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
}
複製代碼

深拷貝結果

beijing
複製代碼

原型,原型鏈

  1. 如何判斷一個變量是否是數組?
  • a instanceof Array
  1. 手寫一個簡易的jquery,考慮插件和擴展性?

代碼:

class jQuery {
    constructor(selector){
        const result = document.querySelectorAll(selector)
        const length = result.length
        for(let i=0; i<length; i++){
            this[i] = result[i]
        }
        this.length = length
    }
    get(index){
        return this[index]
    }
    each(fn){
        for(let i=0;i<this.length;i++){
            const elem = this[i]
            fn(elem)
        }
    }
    on(type,fn){
        return this.each(elem=>{
            elem.addEventListener(type,fn,false)
        })
    }
}
複製代碼

插件的擴展性

jQuery.prototype.dialog = function(info) {
    alert(info)
}
複製代碼

複寫機制:

class myJQuery extends jQuery {
    constructor(selector) {
        super(selector)
    }
    // 擴展本身的方法
    study(){
        
    }
}
複製代碼
  1. class的原型本質,如何理解?
  • 原型和原型鏈的圖示

class相似模板

  • constructor
  • 屬性
  • 方法

代碼:

// 類

class Person {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
    study() {
        console.log('study')
    }
}

// 經過類 new 對象,實例
const web = new Person('哪吒', 10)
複製代碼

class其實是函數,可見的語法糖

typeof Student
結果:
"function"
typeof People
結果:
"function"
複製代碼

繼承

  • extends
  • super
  • 擴展,重寫方法

原型

原型關係:

  1. 每一個class都有顯示原型prototype
  2. 每一個實例都有隱式原型__proto__
  3. 實例的__proto__指向對應classprototype

原型鏈

console.log(Student.prototype.__proto__)
console.log(People.prototype)
console.log(People.prototype === Student.prototype.__proto__)
複製代碼

類型判斷 instanceof

[] instanceof Array // true
[] instanceof Object // true
{} instanceof Object // true
複製代碼

做用域,閉包

  • this的不一樣應用場景下,如何取值?
  • 手寫bind函數
  • 實際開發中閉包的應用場景,舉例說明

建立10個a標籤,點擊彈出對應序號

let i, a
for(i=0; i<10; i++) {
    a=document.createElement('a')
    a.innerHTML = i + '<br>'
    a.addEventListener('click', function(e){
        e.preventDefault()
        alert(i)
    })
    document.body.appendChild(a)
}
複製代碼

做用域

做用域分:

  1. 全局做用域
  2. 函數做用域
  3. 塊級做用域(es6新增)

代碼:

let a = 0
function fn1() {
    let a1 = 100
    function fn2() {
        let a2 = 200
        function fn3() {
            let a3 = 300
            return a+a1+a2+a3
        }
        fn3()
    }
    fn2()
}
fn1()
複製代碼

塊級做用域

if(true) {
    let x=100
}
console.log(x) // 會報錯
複製代碼

自由變量

若是一個變量在當前做用域沒有定義,但被使用了,向上級做用域去找,一層一層一次尋找,直到找到爲止,若是到了全局做用域都沒有找到,就會報錯xx is not defined

閉包

閉包的表現:

  1. 函數做爲參數被傳遞
  2. 函數做爲返回值被返回

作一個簡單的cache工具

閉包隱藏數據

function createCache() {
    const data={}
    // 閉包中的數據,被隱藏,不被外界訪問
    return {
        set: function(key,val) {
            data[key] = val
        },
        get: function(key){
            return data[key]
        }
    }
}

const c = createCache()
c.set('a', 100)
console.log(c.get('a'))
複製代碼

函數做爲返回值

function create(){
    let a = 100
    return function(){
        console.log(a)
    }
}
let fn = create()
let a = 200
fn()
複製代碼

結果:

100
複製代碼

函數做爲參數

function print(fn) {
    let a = 200
    fn()
}

let a = 100
function fn(){
    console.log(a)
}
print(fn)
複製代碼

結果:

100
複製代碼

全部自由變量的查找是在函數定義的地方,向上級做用域查找,不是執行的地方。

this

  1. 做爲普通函數被調用
  2. 使用call,apply,bind被調用
  3. 做爲對象方法被調用
  4. class方法中被調用
  5. 箭頭函數

this取什麼值,是在函數執行的時候肯定的,不是函數定義的時候肯定的。

call指向,bind會返回新的函數

代碼:

function fn1(){
    console.log(this)
}
fn1() // window

fn1.call({x:10}) // {x:10}

const fn2 = fn1.bind({x:20})
fn2() // {x:20}
複製代碼

代碼:

const Jeskson = {
    name: 'web',
    sayHi() {
        // this是指當前對象
        console.log(this)
    },
    wait(){
        setTimeout(function(){
            // this === window
            console.log(this)
        }
    }
}
複製代碼

代碼:

const Jeskson = {
    name: 'web',
    sayHi() {
        // this是指當前對象
        console.log(this)
    },
    wait() {
        setTimeout(()=>{
          // this指當前對象
          console.log(this)
        })
    }
}
複製代碼

代碼:

class People {
    constructor(name){
        this.name = name
        this.age = 20
    }
    sayHi(){
        console.log(this)
    }
}
const Jeskson = new People('web')
Jeskson.sayHi() // Jeskson 對象
複製代碼

手寫bind函數

Function.prototype.bind1 = function(){
    // 將參數解析爲數組
    const args = Array.prototype.slice.call(arguments)
    // 獲取this
    const t = args.shift()
    const self = this // 當前函數
    // 返回一個函數
    return function() {
        // 執行原函數,並返回結果
        return self.apply(t, args)
    }
}
複製代碼

代碼:

function fn1(a,b,c) {
    console.log('this',this)
    console.log(a,b,c)
    return 'this is fn1'
}

const fn2 = fn1.bind ({x:100},10,20,30)
const res = fn2()
console.log(res)
複製代碼

Chrome

fn1.hasOwnProperty('bind')
//false
fn1.__proto__ == Function.prototype
// true
Function.prototype.apply/call/bind
複製代碼

異步,單線程

  1. 同步和異步的區別是什麼?
  2. 手寫用Promise加載一張圖片
  3. 前端使用異步的場景有哪些?

代碼:

// setTimeout筆試題
console.log(1)
setTimeout(function(){
    console.log(2)
},1000)
console.log(3)
setTimeout(function(){
    console.log(4)
},0)
console.log(5)
複製代碼
  1. 單線程和異步
  2. 應用場景
  3. callback hellPromise

JS是單線程語言,同時只能作一件事 瀏覽器和nodejs支持js啓動進程,如web worker JS和dom渲染共用同一線程。

異步:

console.log(100)
setTimeout(function(){
    console.log(200)
},1000)
console.log(300)
複製代碼

同步

console.log(100)
alert(200)
console.log(300)
複製代碼

異步和同步的區別

  1. 基於js是單線程語言
  2. 異步不會阻塞代碼的執行
  3. 同步會阻塞代碼的執行

手寫用Promise加載一張圖片

function loadImg(src) {
    return new Promise(
        (resolve, reject) => {
            const img = document.createElement('img')
            img.onload = () => {
                resolve(img)
            }
            img.onerror = () => {
                const err = new Error(`圖片加載失敗 ${src}`)
                reject(err)
            }
            img.src = src
        }
    )
}

const url = ''
loadImg(url).then(img => {
    console.log(img.width)
    return img
}).then(img => {
    console.log(img.height)
}).catch(ex=>console.error(ex))
複製代碼

異步-單線程

  1. 單線程和異步,異步和同步區別
  2. 前端異步的應用場景
  3. Promise解決callback hell

異步-callback

異步,以回調callback函數形式

異步-應用場景

  1. 網絡請求
  2. 定時任務

第一網絡請求,如ajax圖片加載,第二定時任務,如setTimeout

//ajax
console.log('start')
$.get('./data.json', function(data1){
  console.log(data1)  
})
console.log('end')
複製代碼

圖片的加載

console.log('start')
let img = document.createElement('img')
img.onload = function() {
    console.log('loaded')
}
img.src="/xxx.png"
console.log('end')
複製代碼

代碼應用場景:

// setTimeout
console.log(100)
setTimeout(function(){
    console.log(200)
},1000)
console.log(300)

// setInterval
console.log(100)
setInterval(function(){
    console.log(200)
},1000)
console.log(300)
複製代碼

異步-Promise

Promise代碼:

function getData(url){
    return new Promise((resolve, reject) => {
        $.ajax({
            url,
            success(data) {
                resolve(data)
            },
            error(err) {
                reject(err)
            }
        })
    }
}
複製代碼

Promise

const url1 = '/data1.json'
const url2 = '/data2.json'
const url3 = '/data3.json'
getData(url1).then(data1=>{
    console.log(data1)
    return getData(url2)
}).then(data2 => {
    console.log(data2)
    return getData(url3)
}).then(data3 => {
    console.log(data3)
}).catch(err => console.error(err))
複製代碼

calback hell,回調地獄

代碼:

// 獲取第一個數據
$.get(url1, (data1) => {
    console.log(data1)
    
    // 獲取第二個數據
    $.get(url2, (data2) => {
        console.log(data2)
        
        // 獲取第三個數據
        $.get(url3, (data3) => {
            console.log(data3)
            // 還可能獲取更多的數據
        })
    })
})
複製代碼

DOM,BOM

Dom操做,操做網頁上的Dom元素,瀏覽器上的文本,圖片

Bom操做,操做瀏覽器上的一些事情,瀏覽器的導航,地址等

事件綁定,ajax,存儲

DOM,Document Object Model

  1. DOM是哪一種數據結構
  2. DOM操做的經常使用API
  3. attr和property的區別

DOM的本質,節點操做,結構操做,DOM性能

xml是一種可擴展的標記語言,能夠描述任何結構的數據,html是一種特定的xml

DOM的本質,它就是一顆樹。

  • 獲取Dom節點
  • attribute
  • property

獲取DOM節點

const div1 = document.getElementById('div1') // 元素

const divList = document.getElementsByTagName('div') // 集合

console.log(divlist.length)
console.log(divList[0])

const containerList = document.getElementsByClassName('.container') // 集合

const pList = document.querySelectorAll('p') // 集合
複製代碼

DOM節點的property

const pList = document.querySelectorAll('p');
const p = pList[0]
console.log(p.style.width) // 獲取樣式
p.style.width='100px' // 修改樣式
console.log(p.className) // 獲取class
p.className='p1' // 修改class
// 獲取nodeName 和 nodeType
console.log(p.nodeName)
console.log(p.nodeType)
複製代碼

propertyattribute

property修改對象屬性,不會體現到html結構中

attribute修改html屬性,會改變html結構

兩種都有可能引發DOM從新渲染

DOM結構操做

  1. 新增/插入節點
  2. 獲取子元素列表,獲取父元素
  3. 刪除子元素

新增,插入節點

const div1 = document.getElementById('div1')
// 添加新節點
const p1 = document.createElement('p')
p1.innerHTML = 'this is p1'
div1.appendChild(p1)
const p2 = document.getElementById('p2')
div1.appendChild(p2)
複製代碼

獲取子元素列表和獲取父元素

//獲取子元素列表
const div1 = document.getElementById('div1')
const child = div1.childNodes

//獲取父元素
const div1 = document.getElementById('div1')
const parent = div1.parentNode
複製代碼

刪除節點

const div1 = document.getElementById('div1')
const child = div1.childNodes
div1.removeChild(child[0])
複製代碼

DOM性能

DOM操做會耗費cpu,避免頻繁,對DOM查詢作緩存

DOM查詢作緩存

// 不緩存DOM查詢結果
for(let=0; i<document.getElementsByTagName('p').length;i++) {
    // 每次循環,都會計算length,頻繁進行dom查詢
}
// 緩存dom查詢結果
const pList = document.getElementsByTagName('p')
const length = pList.length
for(let i = 0; i<length; i++){
    // 緩存length,只進行一次dom查詢
}
複製代碼

講頻繁的操做修改成一次性操做

const listNode = document.getElementById('list')

// 建立一個文檔片斷,此時沒有插入到dom樹中
const frag = document.createDocumentFragment();

// 執行插入
for(let x=0; x<10; x++) {
    const li = document.createElement("li")
    li.innerHTML="List item"+x
    frag.appendChild(li)
}

// 都完成後,再插入到dom樹中
listNode.appendChild(frag)
複製代碼

問題:

  1. dom是哪一種數據結構
  2. dom操做的經常使用api
  3. attrproperty的區別
  4. 一次性插入多個dom節點,考慮性能問題

propertyattribute的區別

  1. property修改對象屬性,不會體現到html結構中
  2. attribute修改html屬性,會改變html結構

二者都有可能引發dom從新渲染

  • dom本質
  • dom節點操做
  • dom結構操做
  • dom性能

BOM操做browser object model

問題:如何識別瀏覽器的類型

問題:分析拆解url各個部分

BOM navigator

代碼:

//navigator
const ua = navigator.userAgent
const isChrome = ua.indexOf('Chrome`)
console.log(isChrome)
複製代碼

事件綁定和事件冒泡

  1. 事件監聽函數
  2. 描述事件冒泡的流程

BOM screen

代碼:

//screen
console.log(screen.width)
console.log(screen.height)
複製代碼

BOM location

BOM history

ajax

  1. 手寫一個簡易的ajax
  2. 跨域的經常使用實現方式

ajax XMLHttpRequest

代碼:

//get請求
const xhr = new XMLHttpRequest()
xhr.open('GET','/api', true)
xhr.onreadystatechange = function() {
    // 這裏的函數異步執行
    if (xhr.readyState === 4){
        if(xhr.state === 200) {
            alert(xhr.responseText);
        }
    }
}
xhr.send(null)
複製代碼

ajax 狀態碼

xhr.readyState

  • 0爲尚未調用send()方法
  • 1爲已調用send()方法,正在發送請求
  • 2爲send()方法執行完成,已經接收到所有響應內容
  • 3爲正在解析響應內容
  • 4爲響應內容解析完成,能夠在客戶端調用

xhr.status

  • 2xx表示成功處理請求
  • 3xx表示須要重定向,瀏覽器直接跳轉
  • 4xx表示客戶端請求錯誤
  • 5xx表示服務器端錯誤

ajax 跨域

  1. 什麼是跨域,同源策略
  2. JSONP
  3. CORS,服務器端支持

同源策略-跨域

ajax請求時,瀏覽器要求當前網頁和server必須同源

同源就是:協議,域名,端口,一致

代碼

function ajax(url) {
    const p = new Promise((resolve, reject)=>{
        const xhr = new XMLHttpRequest()
        xhr.open('GET',url,true)
        xhr.onreadystatechange=function(){
            if(xhr.readyState === 4){
                if(xhr.status===2000) {
                    resolve(
                        JSON.parse(xhr.responseText)
                    )
                }else if(xhr.status === 404) {
                    reject(new Error('404 not found'))
                }
            }
        }
        xhr.send(null)
    }
}
複製代碼

事件

  • 事件綁定
  • 事件冒泡
  • 事件代理

事件-綁定

代碼:

const btn = document.getElementById('btn1')
btn.addEventListener('click',event=>{
    console.log('clicked')
})
複製代碼

代碼:

//通用的綁定函數
function bindEvent(elem, type, fn)
    elem.addEventListener(type,fn)
}

const a = document.getElementById('web')
bindEvent(a, 'click', e=>{
    e.preventDefault()
    alert('clicked')
})
複製代碼

事件-冒泡

代碼:

<body>
<div id="div1">
<p id="p1">web</p>
<p id="p2">it</p>
<p id="p3">it</p>
<p id="p4">it</p>
</div>
<div id="div2">
<P id="p5">it</p>
<p id="p6">it</p>
</div>
</body>

const p1 = document.getElementById('p1')
const body = document.body
bindEvent(p1, 'click', e=>{
    e.stopPropagation() // 阻止冒泡
    alert('web')
})
bindEvent(body, 'click', e=>{
    alert('it')
})
複製代碼

事件-代理

代碼:

<div id="div1">
<a href="#">a1</a>
<a href="#">a2</a>
</div>
<button>點擊
</button>

const div1 = document.getElementById('div1')
div1.addEventListener('click', e=>{
 const target = e.target
 if(e.nodeName === 'A') {
     alert(target.innerHTML)
 }
})
複製代碼

事件代理,能夠減小瀏覽器內存佔用

通用的事件綁定函數

const btn1 = document.geteElementById('btn1')
bindEvent(btn1,'click',event=>{
    // console.log(event.target) // 獲取觸發的元素
    event.preventDefault() // 阻止默認行爲
    alert('clicked')
})

const div2 = document.getElementById('div2')
bindEvent(div2,'click',event=>{
    event.preventDefault()
    const target = event.target
    if(target.nodeName === 'A') {
        alert(target.innerHTML)
    }
})
複製代碼

代碼:

function bindEvent(elem, type, selector, fn) {
    if(fn==null) {
        fn = selector
        selector = null
    }
    elem.addEventListener(type, e=>{
        let target
        if(selector) {
            // 須要代理
            target = e.target
            if(target.matches(selector)){
                fn.call(target, e)
            }
        } else {
            // 不須要代理
            fn(e)
        }
    })
}
複製代碼

存儲

cookielocalStoragesessionStorage區別

  1. localStorage數據會永遠存儲,除非代碼回手動刪除
  2. sessionStorage數據只存在於當前會話,瀏覽器關閉則清空

通常用localStorage會更多一些

存儲-cookie

  • 存儲大小,最大4kb
  • http請求時須要發送到服務器端,增長請求數據量
  1. localStorage 和 sessionStorage
  2. html5專門爲存儲而設計的,最大可爲5M
  3. api簡單易用setItemgetItem

不會隨着http請求被髮送出去

存儲-localStorage

代碼:

localStorage.setItem('a',100)
localStorage.getItem('a')
複製代碼

存儲-sessionStorage

代碼:

sessionStorage.setItem('a',100)
sessionStorage.getItem('a')
複製代碼

開發環境

  1. git
  2. 調試工具
  3. 抓包
  4. webpack babel
  5. linux經常使用命令

git

  • 大型項目須要多人協做開發,必用git

代碼:經常使用git命令

git add .
git checkout xxx
git commit -m 'xxx'
git push origin master
git pull origin master

git branch
git checkout -b xxx / git checkout xx
git merge xxx
複製代碼

調式

chrome調試工具

  1. Elements
  2. Network
  3. Console
  4. Application
  5. debugger

調式,抓包

移動端h5頁,查看網絡請求,須要用工具抓包

windows通常用fiddler

webpck和babel

代碼:

const path = require('path')

module.exports = {
    mode: 'development',
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
        filename: 'bundle.js',
        path: path.join(__dirname,'dist')
    }
}
複製代碼

linux命令

線上機器通常都是linux

代碼:

ssh work
ls

rm -rf abc
cd dist
mv index.html index1.html

rm a1.js
touch d.js
rm -rf d.js
複製代碼

運行環境

  1. 運行環境既瀏覽器server端有nodejs
  2. 網頁加載過程
  3. 性能優化
  4. 安全

頁面加載和渲染過程

  1. 從輸入url到渲染出頁面的整個過程
  2. window.onLoad和DOMContentLoaded的區別
  • 加載資源的形式
  • 加載資源的過程
  • 渲染頁面的過程

資源的形式:html代碼,媒體文件,如圖片,視頻等,javascriptcss

加載過程:dns解析,域名,ip地址。瀏覽器根據ip地址向服務器發起http請求。

服務器處理http請求,並返回給瀏覽器。

渲染過程,根據html代碼生成dom tree,根據css代碼生成cssom。講dom treecssom整合行程render tree

根據render tree渲染頁面,遇到script暫停渲染,優先加載並執行js代碼,完成再繼續。

頁面渲染

window.onLoadDOMContentLoaded

代碼:

window.addEventListener('load',function(){
    // 頁面的所有資源加載完纔會執行,包括圖片,視頻等
})
document.addEventListener('DOMContentLoad',function(){
  // dom渲染完既可執行,此時圖片,視頻還可能沒有加載完 
})
複製代碼
  1. window.onload資源所有加載完才能執行,包括圖片
  2. DOMContentLoaded DOM渲染完成便可,圖片可能還沒下載

性能優化

手寫防抖,節流

原則:

  1. 多使用內存,緩存或其餘方法
  2. 減小cpu計算量,減小網絡加載耗時

讓加載更快,渲染更快,減小資源體積。減小訪問次數,合併代碼,ssr服務器端渲染,緩存。

dom查詢進行緩存,頻繁dom操做,合併到一塊兒插入dom結構,節流throttle防抖debounce

ssr

服務器端渲染,講網頁和數據一塊兒加載,一塊兒渲染

非ssr,先加載網頁,再加載數據,再渲染數據

懶加載

代碼:

<img id="img1" src="preview.png" data-realsrc="abc.png"/>
<script type="text/javascript">
var img1 = document.getElementById('img1')
img1.src = img1.getAttribute('data-realsrc')
</script>
複製代碼

防抖debounce

  1. 監聽一個輸入框,文字變化後觸發change事件
  2. 直接用keyup事件,則會頻繁觸發change事件

防抖,用戶輸入結束或暫停時,纔會觸發change事件。

代碼:

const input1 = document.getElementById('input1')
input1.addEventListener('keyup', function(){
    console.log(input1.value)
}}
複製代碼

代碼:

const input1 = document.getElementById('input1')
let timer = null
input1.addEventListener('keyup', function(){
    if(timer){
        clearTimeout(timer)
    }
    timer = setTimeout(()=>{
        // 模擬觸發change事件
        console.log(input1.value)
        // 清空定時器
        timer = null
    },500)
})
複製代碼

debounce防抖代碼:

function debounce(fn, delay = 500) {
    // timer 是閉包中的
    let timer = null
    return function() {
        if(timer) {
            clearTimeout(timer)
        }
        timer = setTimeout(()=>{
            fn.apply(this, arguments)
            timer = null
        },delay)
    }
}

input1.addEventListener('keyup', debounce(()=>{
    console.log(input1.value)
}),600)
複製代碼

節流throttle

拖拽一個元素時,要隨時拿到該元素被拖拽的位置

代碼:

const div1 = document.getElementById('div1')
let timer = null
div1.addEventListener('drag',function(e){
    if(timer){
        return
    }
    timer = setTimeout(()=>{
        console.log(e.offsetX, e.offsetY)
        timer = null
    },100)
})
複製代碼

節流代碼:

function throttle(fn, delay = 100) {
    let timer = null
    return function() {
        if(timer) {
            return
        }
        timer = setTimeout(()=>{
            fn.applay(this,arguments)
            timer = null
        },delay)
    }
}

div1.addEventListener('drag',throttle(function(e){
    console.log(e.offsetX,e.offsetY)
},200))
複製代碼

web安全

  1. 前端web常見的攻擊方式有哪些?

  2. xss跨站請求攻擊

  3. xsrf跨站請求僞造

運行環境

  1. 頁面加載:加載,渲染
  2. 性能優化:加載資源優化,渲染優化
  3. 安全:xss,csrf

總結

什麼是變量提高

  1. var 和 let const 的區別
  2. typeof返回哪些類型
  3. 舉例強制類型轉換和隱式類型轉換

var和let const 的區別

var是es5的語法,let const 是es6語法,var有變量提高

var和Let是變量,const是常量,不可修改

let const有塊級做用域,var沒有

object和function

強制類型轉換和隱式類型轉換

強制:parseInt,parseFloat,toString等

isEqual

  1. 手寫深度比較
  2. split()和join()的區別
  3. 數組,pop,push,unshift,shift

lodash.isEqual

//實現以下效果
const obj1 = {a:10, b:{x:100,y:200}}
const obj2 = {a:10, b:{x:100,y:200}}
isEqual(objq,obj2) === true
複製代碼

判斷是不是對象或數組

代碼:

function isObject(obj){
    return typeof ojb === 'object' && obj !== null
}
// 全相等
function isEqual(obj1,obj2){
    if(!isObject(obj1) || !isObject(obj2)) {
        // 值類型
        return obj1===obj2
    }
    if(obj1===obj2){
        return true
    }
    // 兩個都是對象或數組,並且不相等
    const obj1key = Object.keys(obj1)
    const obj2key = Object.keys(obj2)
    
    if(obj1key.length !== obj2key.length){
        return false
    }
    for(let key in obj1){
        const res = isEqual(obj1[key],obj2[key])
        if(!res){
            return false
        }
    }
    return true
}
複製代碼

split()和join()的區別

'1-2-3'.split('-') // [1,2,3]
[1,2,3].join('-') // '1-2-3'
複製代碼

數組的pop,push,unshift,shift

功能分別是什麼,返回值是什麼,有什麼影響。

pop返回刪除的最後一個值

push返回追加後元素的長度

unshift插入到最前面,返回長度length

shift刪除最前面的,返回刪除的值

  • pop,shift-》返回值
  • unshift, push-》length

  1. 數組slice和splice的區別
  2. [10,20,30].map(parseInt)返回結果
  3. ajax請求get和post的區別

  • get用於查詢,post用於提交
  • get參數拼接在url上,post放在請求體內

call和apply的區別

代碼:

fn.call(this, p1,p2,p3)
fn.apply(this, argument)
複製代碼

事件代理是什麼

代碼:

const p1 = document.getElementById('p1')
const body = document.body

bindEvent(p1, 'click', e=>{
    e.stopProgation();
    alert()
})
bindEvent(body, 'click', e=>{
    alert()
})
複製代碼

閉包是什麼,有什麼特性,有什麼負面影響

  1. 做用域和自由變量

自由變量的查找,要在函數定義的地方,不是執行的地方

閉包不要亂用,變量會常駐內容,不會釋放

閉包:

function create() {
    let a=100
    return function(){
        console.log(a)
    }
}
let fn = create()
let a=200
fn() // 100
複製代碼
  1. 如何阻止事件冒泡和默認行爲?
  2. 查找,添加,刪除,移動dom節點的方法
  3. 如何減小dom操做
  • event.stopPropagation()
  • event.preventDefault()

代碼:

// 新建節點
const newP = document.createElement('p')
newP.innerHTML = 'this is newP'
// 插入節點
div1.appendChild(newP)
// 移動節點
const p1 = document.getElementById('p1')
div2.appendChild(p1)
//獲取父元素
console.log(p1.parentNode)
複製代碼

如何減小dom操做

  1. 緩存dom查詢結果
  2. 屢次dom操做,合併到一次插入

代碼:

const list = document.getElementById('list')
const frag = document.createDocumentFragment()

for(let i=0; i<20; i++){
    const li = document.createElement('li')
    li.innerHTML = 'list'
    frag.appendChild(li)
}
list.appendChild(frag)
複製代碼

jsonp的原理,爲何它不是真正的ajax

瀏覽器的同源策略和跨域

document load 和 ready的區別

load:

頁面的區別資源加載完纔會執行

ready:

dom渲染完既可執行,圖片,視頻等尚未加載完

函數聲明和函數表達式的區別

函數聲明

function fn(){...}

函數表達式:

const fn = function(){...}

函數聲明會預加載,而函數表達式不會

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

  • {}等同new Object(),原型Object.prototype

場景題1

代碼:

let i 
for (i = 1; i <= 3; i++) {
    setTimeout(function(){
        console.log(i)
    },0)
}
複製代碼

場景2

代碼:

let a = 100
function test() {
    alert(a)
    a = 10
    alert(a)
}
test()
alert(a)
複製代碼

場景3

手寫字符串trim方法,保證瀏覽器兼容性

用Js實現繼承

場景4

  1. 如何捕獲Js程序中的異常
  2. 什麼是json
  3. 獲取當前頁面url參數

代碼:

try {
    // todo
}catch(error) {
    console.error(error)
}finally{
    
}
複製代碼

json是一種數據格式,本質是一段字符串,json格式和js對象結構一致。

window.JSON是一個全局對象,JSON。stringifyJSON.parse

獲取當前頁面url參數

傳統方式,查找location.search

api,URLSearchParams

場景5

  1. 講url參數解析爲js對象
  2. 手寫數組flatern
  3. 數組去重

代碼:

// 1
function queryToObj(){
    const res={}
    const search = location.search.substr(1)
    search.split('&').forEach(res => {
        const arr = res.split('=')
        const key = arr[0]
        const key = arr[1]
        res[key] = val
    })
}
複製代碼

使用URLSearchParams

function queryToObj() {
    const res = {}
    const pList = new URLSearchParams(location.search)
    pList.forEach((val,key) => {
      res[key] = val  
    })
    return res
}
複製代碼

手寫數組flatern

代碼:

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
}
複製代碼

使用Set

function unique(arr) {
    const set = new Set(arr)
    return [...set]
}
複製代碼

場景6

  1. 手寫深拷貝
  2. 使用RAF requestAnimateFrame
  3. 前端性能的優化

代碼:

function deepClone(obj = {}) {
    if(type of obj !== 'object' || obj == null){
        return obj
    }
    let result
    if(obj instanceof Array) {
        result = []
    }else{
        result = {}
    }
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            result[key] = deepClone(obj[key])
        }
    }
    return result
}
複製代碼

Object.assign不是深拷貝!

性能優化

原則:多使用內存,緩存,減小計算,網絡請求

加載頁面,頁面渲染,頁面操做等多多思考問題。

最後

歡迎加我微信Jeskson(xiaoda0423),拉你進技術羣(掘金-前端高校),長期交流學習。

相關文章
相關標籤/搜索