記頭條的一次筆試

習空發表於2019-04-12

四月初收到了頭條的筆試邀請,開啟連結後發現跳到了牛客網。面試前心中很是忐忑,畢竟大廠,而自己面試經驗又不多。

最後做下來,發現自己確實還有很多不足,尤其是手擼程式碼這一塊。有些 js 方法就是記不住,比如日期獲取年,下意識寫了 date.getYear(),其實是不對的,應該是 date.getFullYear()

話不多說,看題吧。期望能給予同在面試的你或他一點幫助!

題一:正則考點

給出一個段文字,將文字內容輸出為特定內容

文字

aa "55" $c b
nn (8*) q 12
true sdc 12 2w2
複製程式碼

輸出

輸出

這是筆試的第一題,看到題目後下意識想這個文字是怎麼輸入進去的?在瀏覽器端,js 不能讀取檔案吧。反正很是糾結。

大概過了 5 分鐘,遲遲無法答題。最後乾脆忽略文字檔案讀取,直接當有換行符的文字字串處理。但是換行這一塊在大腦中搜尋不到任何資訊,唉,最後答了一個使用 /\S/ 正規表示式處理,然後進入下一題。


以下是筆試完後寫的:

<input class="file" type="file">
<script>
    var file = document.querySelector('.file')
    file.addEventListener('change', function(e) {
        var fileRead = new FileReader()
        fileRead.readAsText(e.target.files[0])
        fileRead.onload = function() {
            var text = fileRead.result
            text = text.match(/[\s\S]+/g)[0]
            var textArr = text.split(/[\r\n]+/)
            var arr = []
            textArr.forEach(function(item) {
                arr.push(item.split(/\s+/))
            })
            console.log(arr)
        }
    })
</script>
複製程式碼

因為題目沒有說清楚,所以假想它是需要讀取一個文字檔案裡面的內容。當然,也可以直接使用正則匹配那部分程式碼。

題二:佈局考點

CSS 內容,一個簡單的 sticky footer 佈局。大致內容就是當頁面高度不夠時,頁尾固定在頁面底部;當頁面高度足夠時,頁尾被頁面內容推送下去。

<header>
 <h1>Header</h1>
</header>
<main>
  <p>Bacon Ipsum dolor sit amet...</p>
</main>
<footer>
  <p>Footer</p> 
</footer>
複製程式碼
html {
  height: 100%;
}
body {
  display: flex;
  flex-direction: column;
  min-height: 100%;
}
main {
  flex: 1;
}
複製程式碼

題三:Date 與程式設計能力考點

一個時間轉換問題,輸入一個時間戳或時間字串,然後與當前時間對比。

如果1分鐘以內,顯示剛剛;如果小於2分鐘,顯示2分鐘前;如果小於1小時,顯示1小時前;如果小於1小天,顯示1天前;如果大於2天,顯示日期字串,"2019-03-20"

function format(time) {
    time = new Date(time)
    var interval = new Date() - time
    if (interval < 60 * 1000) {
        return '剛剛'
    } else if (interval < 60 * 60 * 1000) {
        return Math.floor(interval / (60 * 1000)) + '分鐘前'
    } else if (interval < 24 * 60 * 60 * 1000) {
        return Math.floor(interval / (60 * 60 * 1000)) + '小時前'
    } else if (interval < 2 * 24 * 60 * 60 * 1000) {
        return Math.floor(interval / (24 * 60 * 60 * 1000)) + '小時前'
    } else {
        return time.getFullYear() + '-' + (addZero(time.getMonth() + 1)) + '-' + addZero(time.getDay())
    }
}

function addZero(number) {
    return number < 10 ? ('0' + number) : number
}

console.log(format('2019-4-10 9:25:01'))
console.log(format(1555040105650))
複製程式碼

題四:計算機基礎考點

正數和負數,其原碼、反碼、補碼的關係。

這題很簡單,不過突然一下子想不起來了。當時記混了,說正數的補碼是反碼加一。

  • 正數:原碼、反碼、補碼都相同
  • 負數:反碼等於原碼取反,補碼等於反碼加一

題五:設計模式考點

實現一個事件類 Event,包括 on(),off(),once(),emit() 方法

class Event {
    constructor() {
        this.events = {}
    }
    on(event, callback) {
        if (!this.events[event]) {
            this.events[event] = []
        }
        this.events[event].push(callback)
    }
    off(event, callback) {
        if (this.events[event]) {
            this.events[event] = this.events[event].filter(fn => callback !== fn)
        }
    }
    once(event, callback) {
        let _this = this
        if (!_this.events[event]) {
            _this.events[event] = []
        }
        const fn = function() {
            callback.apply(_this, arguments)
            _this.off(event, fn)
        }
        _this.events[event].push(fn)
    }
    emit(event, data) {
        if (this.events[event]) {
            this.events[event].forEach(function(callback) {
                callback(data)
            })
        }
    }
}

let event1 = new Event()
event1.once('abc', function(data) {
    console.log('1', data)
})
event1.on('abc', function(data) {
    console.log('2', data)
})
event1.emit('abc', 521)
event1.emit('abc', 520)
複製程式碼

題六:效能優化與事件委託考點

有一個表格 table,點選其中 td 元素,可以彈出元素裡的文字內容。

<table class="table" border="1">
    <tr>
        <td>Hi</td>
        <td>Ha</td>
        <td>Ho</td>
    </tr>
</table>
<script>
    var table = document.querySelector('table')
    table.addEventListener('click', function(event) {
        if (event.target.nodeName.toLowerCase() === 'td') {
            alert(event.target.innerHTML)
        }
    })
</script>
複製程式碼

題七:正則與程式設計能力考點

數字金額千分位轉換,如 14290023.2314,290,023.23,使用正則和非正則兩種方式

老實說前些天我還特意看了千分位轉換的,但是當時看別人的正則實現很頭疼,所以只是過了下。筆試時,正則這一塊沒答出來。然後寫了一個非正則的。

function formatRegExp1(number) {
    var pattern = /(?=(\B\d{3})+\.)/g
    return number.toFixed(2).toString().replace(pattern, ',')
}

function formatRegExp2(number) {
    var pattern = /(\d)(?=(?:\d{3})+\.)/g
    return number.toFixed(2).toString().replace(pattern, '$1,')
}

function format(number) {
    number = number.toFixed(2).toString()
    var dotIndex = number.indexOf('.')
    var part = number.substring(0, dotIndex)
    var flag = 0
    var result = ''
    for (var i = part.length - 1; i >= 0; i--) {
        result = part[i] + result
        if (i !== 0 && ++flag === 3) {
            result = ',' + result
            flag = 0
        }
    }
    return result + number.substring(dotIndex)
}

console.log(format(114290023))
console.log(format(2114290023))
複製程式碼

題八:this 指向考點

這道題在最開始寫本文時漏掉了,想了想還是補上,萬一有人忽略了這個知識點呢(其實是我自己不會這個知識點啦 -_-)

var obj1 = {
    name: 'obj1'
}
var obj2 = {
    name: 'obj2'
}
var obj3 = {
    name: 'obj3'
}
function say() {
    console.log(this.name)
}
var fn = say.bind(obj1).bind(obj2).bind(obj3)
fn()
複製程式碼

結果是 obj1,表面原因是 bind() 只對第一次有效。但是這是為什麼呢?追本溯源,我們來看看本質是啥。

bind() 的實現:

Function.prototype.bind = function(context) {
    const self = this
    const args = [...arguments].slice(1)
    return function F() {
        if (self instanceof F) {
            return new self(...args, ...arguments)
        }
        return self.apply(context, args.concat(...arguments))
    }
}
複製程式碼

題目程式碼:

var s1 = say.bind(obj1)
s1 = function() {
    return say.apply(obj1)
}

var s2 = s1.bind(obj2)
s2 = function() {
    return (function() {
        return say.apply(obj1)
    }).apply(obj2)
}

var s3 = s1.bind(obj3)
s3 = function() {
    return (function() {
        return (function() {
            return say.apply(obj1)
        }).apply(obj2)
    }).apply(obj3)
}

s3()
複製程式碼

由此可以看到 say() 方法的 this 指向就是 obj1

小結

總體來說,題目是不難的,但是很考驗候選人的綜合能力。如果你也面試前端,並且將來也恰好遇到了套試題,不要高興的太早。雖然他能幫助你通過筆試,但是後面的面試更難。

相關文章