avatar

目录
前端手写代码题

前言

最近整理了一些前端方向常见的手写代码题,动手实现一遍之后,对一些常见的API或者组件原理有了更多的理解,故在此做一下记录和分享😁😁


基础

请求相关

  1. 原生ajax实现

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    const Ajax = {
    // data应为'a=a1&b=b1'这种字符串格式,在jq里如果data为对象会自动将对象转成这种字符串格式
    post: function (url, data, callback) {
    var xhr = new XMLHttpRequest();
    xhr.open('POST', url, false);
    // 添加http头,发送信息至服务器时内容编码类型
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.onreadystatechange = function () {
    if (xhr.readyState == 4 && xhr.status == 200) {
    callback(JSON.parse(xhr.responseText));
    }
    }
    xhr.send(JSON.stringify(data));
    }
    }

    Ajax.post('/data', { name: 'xiaoming' }, data => {
    console.log('data: ', data)
    })
  2. websocket

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var ws = new WebSocket("ws://localhost:8080");
    ws.onopen = function () {
    console.log("open");
    ws.send("hello"); //将消息发送到服务端
    }
    ws.onmessage = function (e) {
    console.log(e.data);
    }
    ws.onclose = function (e) {
    console.log("close");
    }
    ws.onerror = function (e) {
    console.log(error);
    }
  3. fetch

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    fetch('/data', {
    method: 'POST',
    headers: {
    'content-type': 'application/json',
    },
    body: JSON.stringify({ name: 'xiaoming' }),
    credentials: 'same-origin'
    })
    .then(response => {
    if (response.ok) {
    return response.json()
    }
    return Promise.reject('server error: ' + response.status)
    })
    .then(data => {
    console.log(data)
    })
    .catch(error => console.error('catch error:', error))
  4. jsonp的实现

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    let jsonpFunc = () => {}
    function jsonp(url, delay) {
    return new Promise((resolve, reject) => {
    jsonpFunc = resolve
    const body = document.getElementsByTagName('body')[0]
    const script = document.createElement('script')
    script.src = url
    body.appendChild(script)

    setTimeout(() => {
    reject('timeout')
    }, delay)
    })
    }

    jsonp('./js/index.js?name=jsonpFunc', 1000)
    .then(res => {
    console.log(res)
    }, err => {
    console.log(err)
    })

Promise

  1. Promise的简单实现

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    // todo: error的向后传递特性
    class _Promise {
    constructor(fn) {
    /**
    * state promise状态
    * onFullFilled 兑现之后的回调函数
    * onRejected 拒绝之后的回调函数
    * onCatch catch函数
    */
    this.state = 'pending'
    this.onFullFilled = null
    this.onRejected = null
    this.onCatch = null

    this.nextResolve = null
    this.nextReject = null

    fn(this.resolve, this.reject)
    }

    then = (onFullFilled, onRejected) => {
    this.onFullFilled = onFullFilled
    this.onRejected = onRejected

    // 链式调用
    return new _Promise((resolve, reject) => {
    this.nextResolve = resolve
    this.nextReject = reject
    })
    }

    resolve = data => {
    this.state = 'fullFilled'
    let returnValue
    if (this.onFullFilled) {
    returnValue = this.onFullFilled(data)
    }

    if (this.nextResolve) {
    this.nextResolve(returnValue)
    }
    }

    reject = error => {
    this.state = 'rejected'
    if (this.onRejected) {
    this.onRejected(error)
    } else if (this.onCatch) {
    this.onCatch(error)
    } else {
    this.nextReject(error)
    }
    }

    catch = fn => {
    this.onCatch = fn
    }
    }


    const getData = new _Promise((resolve, reject) => {
    setTimeout(() => {
    // resolve('data')
    reject('error')
    }, 1000)
    })


    getData
    .then(res => {
    console.log('1', res)
    })
    .then(res => {
    console.log('2', res)
    }, err => {
    console.log('2 err', err)
    })
    .catch(err => {
    console.log('catch error', err)
    })
  2. Promise.all的简单实现

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    Promise._all = promises => {
    const resList = []
    let count = 0

    return new Promise((resolve, reject) => {
    promises.forEach((item, index) => {
    item
    .then(res => {
    count++
    resList[index] = res
    if (count === promises.length) {
    resolve(resList)
    }
    }, error => {
    reject(error)
    })
    })
    })
    }

    const promise1 = new Promise((resolve, reject) => {
    resolve(1);
    // reject(1);
    });
    const promise2 = new Promise((resolve, reject) => {
    resolve(2);
    });
    const promise3 = new Promise((resolve, reject) => {
    resolve(3);
    });

    Promise._all([promise1, promise2, promise3])
    .then(res => {
    console.log(res);
    }, error => {
    console.log(error)
    })

  3. Promise并发限制

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    class PromisePool {
    constructor(promiseProducers, limit) {
    /**
    * promiseProducers promise生产者列表
    * limit 最大并发数
    * res 请求返回数据
    * index 目前发起请求的index
    * sum promise个数
    * count promise成功个数
    * resolve 全部promise成功之后的要执行的函数
    */
    this.promiseProducers = promiseProducers
    this.limit = limit
    this.res = []
    this.index = limit - 1
    this.sum = promiseProducers.length
    this.count = 0
    this.resolve = null
    }

    // 启动并发请求
    start() {
    const curPromiseProducers = this.promiseProducers.splice(0, this.limit)
    curPromiseProducers.forEach((item, index) => {
    this.runTask(item, index)
    })

    return new Promise(resolve => {
    this.resolve = resolve
    })
    }

    // 单个请求
    runTask(promiseProducer, index) {
    promiseProducer().then(res => {
    this.res[index] = res
    this.count++

    if (this.promiseProducers.length > 0) {
    this.index++
    this.runTask(this.promiseProducers.shift(), this.index)
    }

    if (this.count === this.sum) {
    this.resolve(this.res)
    }
    })
    }
    }

    const urls = [
    'bytedance.com',
    'tencent.com',
    'alibaba.com',
    'microsoft.com',
    'apple.com',
    'hulu.com',
    'amazon.com',
    ]
    const requestFn = url => {
    return new Promise(resolve => {
    setTimeout(() => {
    resolve(`任务${url}数据`)
    }, 1000)
    })
    }
    const promiseProducers = urls.map(item => requestFn.bind(null, item))

    // 最大并发数3
    const pool = new PromisePool(promiseProducers, 3)
    pool.start()
    .then(res => {
    console.log(res)
    })

async/await 简单实现

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function autoRun(func) {
const generator = func()
const next = (data) => {
const result = generator.next(data)
if (result.done) {
return result.value
}
result.value.then(res => {
next(res)
})
}
next()
}

const getData = name => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`get data: ${name}`)
}, 100)
})
}

const initData = function* () {
const data1 = yield getData('xiaohong')
const data2 = yield getData('xiaoming')

console.log('data1: ', data1)
console.log('data2: ', data2)
}

autoRun(initData)

new原理

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function _new(func, ...rest) {
const obj = Object.create(func.prototype)
const res = func.apply(obj, rest)

return typeof res === 'object' ? res : obj
}

function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.say = function() {
console.log('say something')
}
const person1 = _new(Person, 'xiaoming', 19)
console.log(person1)

bind原理

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Function.prototype._bind = function (context, ...rest) {
const _this = this
const bindFunc = function (...restChild) {
// new调用的时候,this会把bindFunc的原型也带过来,所以可以以此区分是普通调用还是new调用
_this.apply(
_this.prototype.isPrototypeOf(this) ? this : context,
[...rest, ...restChild]
)
}
bindFunc.prototype = Object.create(_this.prototype)

return bindFunc
}

function foo(name, age) {
console.log(`${this.type}: my name is ${name}, I am ${age} year old.`);
}
var obj = { type: 'Animal' };
// const newFoo = foo.bind(obj, 'xiaoming')
const newFoo = foo._bind(obj, 'xiaoming')
newFoo('13')
new newFoo('13')

继承

  1. 构造函数继承

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    function Animal(name) {
    this.name = name
    }

    Animal.prototype.sleep = function () {
    console.log('sleep')
    }

    function Cat(name, color) {
    Animal.call(this, name)
    this.color = color
    }
    Cat.prototype = new Animal()
    Cat.prototype.walk = function () {
    console.log('walk')
    }

    const myCat = new Cat('my litter cat', 'black')
    myCat.sleep()
    myCat.walk()
    console.log('name:', myCat.name, 'color: ', myCat.color)
  2. ES6 class语法继承

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class Animal {
    constructor(name) {
    this.name = name
    }

    sleep() {
    console.log('sleep')
    }
    }

    class Cat extends Animal {
    constructor(name, color) {
    super(name)
    this.color = color
    }

    walk() {
    console.log('walk')
    }
    }

    const myCat = new Cat('my litter cat', 'black')
    myCat.sleep()
    myCat.walk()
    console.log('name:', myCat.name, 'color: ', myCat.color)
  3. 对象关联(js继承的本质)

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    const animal = {
    name: 'animal',
    sleep() {
    console.log('sleep')
    }
    }

    const cat = {
    name: 'cat',
    walk() {
    console.log('walk')
    }
    }

    Object.setPrototypeOf(cat, animal)

    console.log(cat.name)
    cat.sleep()

React virtual DOM

html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<div id="container" class="container">
test
</div>

<script type="text/javascript">
// API
class Element {
constructor(type, props, children) {
this.type = type
this.props = props
this.children = children
}
}

function createElement(type, props, children) {
return new Element(type, props, children)
}

function renderDom(element) {
const dom = document.createElement(element.type)
for (let [key, value] of Object.entries(element.props)) {
dom.setAttribute(key, value)
}
element.children.forEach(item => {
let childDom = null
if (item instanceof Element) {
childDom = renderDom(item)
} else {
childDom = document.createTextNode(item)
}
dom.appendChild(childDom)
})
return dom
}

function renderToRoot(element, target) {
const dom = renderDom(element)
target.appendChild(dom)
}

// 使用示例
const virtualDom = createElement(
'ul',
{ class: 'list' },
[
createElement('li', { class: 'item' }, ['a']),
createElement('li', { class: 'item' }, ['b']),
createElement('li', { class: 'item' }, ['c']),
]
)
renderToRoot(virtualDom, document.getElementById('container'))

</script>

shadow dom 的基本使用

html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<div id="container" class="container">
<span class="shadow-host">
<a href="https://twitter.com/ireaderinokun">
Follow @ireaderinokun
</a>
</span>
</div>

<script type="text/javascript">

window.onload = function () {
const shadowEl = document.querySelector(".shadow-host");
// 挂载shadow dom节点,会覆盖原有的字节点
const shadow = shadowEl.attachShadow({ mode: 'open' });

// 添加dom节点
const link = document.createElement('a')
link.href = 'https://twitter.com/ireaderinokun'
link.innerHTML = 'Follow @ireaderinokun'
shadow.appendChild(link)

// 添加style标签,增加样式
const styles = document.createElement("style");
styles.textContent = `
a {
vertical - align: top;
display: inline - block;
box - sizing: border - box;
}
`
shadow.appendChild(styles);
}

</script>

Redux 简易版

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// API
function createStore(reducer) {
let state = reducer(undefined, {})
const listeners = []

const subscribe = listener => listeners.push(listener)
const getState = () => state
const dispatch = action => {
state = reducer(state, action)
listeners.forEach(listener => listener())
}
return { subscribe, getState, dispatch }
}

function combineReducers(reducerMap) {
const initState = {}
for (let [key, value] of Object.entries(reducerMap)) {
initState[key] = value(undefined, {})
}

return function reducer(state = initState, action) {
const allState = {}
for (let [key, value] of Object.entries(reducerMap)) {
allState[key] = value(state[key], action)
}
return allState
}
}


// 使用示例
function counterReducer(state = { value: 0 }, action) {
switch (action.type) {
case 'counter/incremented':
return { value: state.value + 1 }
case 'counter/decremented':
return { value: state.value - 1 }
default:
return state
}
}

function nameReducer(state = { name: 'xiaoming' }, action) {
switch (action.type) {
case 'name/incremented':
return { name: state.name + 1 }
case 'name/decremented':
return { name: state.name - 1 }
default:
return state
}
}

let store = createStore(combineReducers({
count: counterReducer,
name: nameReducer,
}))

console.log('initial state: ', store.getState()) // initial state: { count: { value: 0 }, name: { name: 'xiaoming' } }

store.subscribe(() => console.log(store.getState()))

store.dispatch({ type: 'counter/incremented' }) // { count: { value: 1 }, name: { name: 'xiaoming' } }
store.dispatch({ type: 'counter/incremented' }) // { count: { value: 2 }, name: { name: 'xiaoming' } }
store.dispatch({ type: 'name/incremented' }) // { count: { value: 2 }, name: { name: 'xiaoming1' } }

React-router-dom 简易版

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function Login() {
return <div>login</div>
}

function Register() {
return <div>register</div>
}

function App() {
const [pathName, setPathName] = useState(window.location.pathname)
const goToLogin = () => {
setPathName('login')
window.history.pushState(null, '', 'login')
}
const goToRegister = () => {
setPathName('register')
window.history.pushState(null, '', 'register')
}

const showModules = () => {
switch (pathName) {
case 'login':
return <Login />
case 'register':
return <Register />
default:
return <div>404</div>
}
}

return (
<div className="App">
App
<div className="nav">
<button onClick={goToLogin}>login</button>
<button onClick={goToRegister}>register</button>
</div>
{showModules()}
</div>
)
}

Node.js 中间件

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// API
function app() {
const middlewareList = []
let middlewareListIndex = 0
let callbackFn = null
let req = null
let res = null

const run = () => {
if (middlewareList.length > middlewareListIndex) {
const curMiddleware = middlewareList[middlewareListIndex]
middlewareListIndex++
curMiddleware(req, res, run)
} else {
callbackFn(req, res)
}
}

const use = middleware => {
middlewareList.push(middleware)
}

const get = (url, callback) => {
req = { type: 'request' }
res = { type: 'response' }
callbackFn = callback

run(req, res)
}

return { use, get }
}

// 使用示例
const server = app();
const middlewareOne = (req, res, next) => {
console.log('注册验证');
next();
}
const middlewareTwo = (req, res, next) => {
console.log('注册成功');
next();
}
server.use(middlewareOne);
server.use(middlewareTwo)

server.get('/login', (req, res) => {
console.log(req, res)
})

排序算法

  1. 冒泡排序

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function bubbleSort(arr) {
    const list = [...arr]
    for (let i = 0; i < list.length - 1; i++) {
    for (let j = 0; j < list.length - i - 1; j++) {
    if (list[j] > list[j + 1]) {
    [list[j], list[j + 1]] = [list[j + 1], list[j]]
    }
    }
    }
    return list
    }
  2. 选择排序:找到数据结构中的最小值,并将其放在第一位,接著找第二小的值放在第二位,以此类推

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function selectionSort(arr) {
    const list = [...arr]
    let minIndex = 0
    for (let i = 0; i < list.length; i++) {
    minIndex = i
    for (let j = i; j < list.length; j++) {
    if (list[j] < list[minIndex]) {
    minIndex = j
    }
    }
    [list[i], list[minIndex]] = [list[minIndex], list[i]]
    }
    return list
    }
  3. 插入排序:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function insertionSort(arr) {
    const list = [...arr]
    for (let i = 0; i < arr.length; i++) {
    const temp = list[i]
    for (let j = i; j > 0; j--) {
    if (temp < list[j - 1]) {
    list[j] = list[j - 1]
    } else {
    list[j] = temp
    break
    }
    }
    }
    return list
    }
  4. 归并排序O(nlog_n):将原数组切分成较小的数组,直到每个小数组只有一个位置,接着将小数组归并成较大的数组,直到最后只有一个排序完毕的大数组

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function mergeSort(arr) {
    const list = [...arr]
    const merge = (leftList, rightList) => {
    const mergeList = []
    while (leftList.length && rightList.length) {
    mergeList.push(leftList[0] < rightList[0] ? leftList.shift() : rightList.shift())
    }
    return mergeList.concat(leftList, rightList)
    }

    if (list.length < 2) return list

    const mid = Math.floor(list.length / 2)
    return merge(mergeSort(list.slice(0, mid)), mergeSort(list.slice(mid)))
    }
  5. 快速排序:在数组中间选择一个主元,交换两边的元素,让主元左边的元素小于主元,右边的元素大于主元;再对两边重复这个步骤;

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    function quickSort(array) {
    const newArr = [...array]

    const sort = (list, left, right) => {
    if (left >= right) return

    let i = left
    let j = right
    const base = list[left]
    while (i < j) {
    // 从右边起,寻找比基数小的数
    while (i < j && list[j] >= base) {
    j--
    }
    // 从左边起,寻找比基数大的数
    while (i < j && list[i] <= base) {
    i++
    }
    [list[i], list[j]] = [list[j], list[i]]
    }
    list[left] = list[i]
    list[i] = base

    sort(list, left, i - 1)
    sort(list, i + 1, right)
    }
    sort(newArr, 0, newArr.length - 1)
    return newArr
    }
  6. 堆排序:https://segmentfault.com/a/1190000015487916

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    function heapSort(arr) {
    const list = [...arr]
    const heapify = (list, i, size) => {
    const left = 2 * i + 1
    const right = 2 * i + 2
    let maxIndex = i

    if (left < size && list[left] > list[maxIndex]) {
    maxIndex = left
    }
    if (right < size && list[right] > list[maxIndex]) {
    maxIndex = right
    }

    if (maxIndex !== i) {
    [list[i], list[maxIndex]] = [list[maxIndex], list[i]]
    heapify(list, maxIndex, size)
    }
    }
    const buildHeap = list => {
    for (let i = Math.floor(list.length / 2) - 1; i >= 0; i--) {
    heapify(list, i, list.length)
    }
    }
    // 建大顶堆
    buildHeap(list)
    // 拿出堆顶(最大值),剩下的节点再调整成大顶堆
    for (let size = list.length - 1; size > 0; size--) {
    [list[0], list[size]] = [list[size], list[0]]
    heapify(list, 0, size)
    }
    return list
    }

发布订阅模式

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const Event = (function () {
const clientList = {}

const listen = (key, fn) => {
if (!clientList[key]) {
clientList[key] = []
}
clientList[key].push(fn)
};

const trigger = (key, ...rest) => {
const fns = clientList[key]
if (!fns || fns.length === 0) {
return false
}
for (var i = 0, fn; fn = fns[i++];) {
fn.apply(null, rest)
}
};

return {
listen,
trigger,
}
})()

Event.listen('squareMeter88', function (price) {
console.log('价格=' + price)
})

Event.trigger('squareMeter88', 20000)

对象深拷贝

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const deepCopy = variable => {
const type = Object.prototype.toString.call(variable).slice(8, -1)

switch (type) {
case 'Object':
const obj = {}
for (let key of Object.keys(variable)) {
obj[key] = deepCopy(variable[key])
}
return obj
case 'Array':
return variable.map(item => deepCopy(item))
case 'Function':
return new Function(`return ${variable.toString()}`).call(this)
case 'Date':
return new Date(variable.valueOf())
case 'RegExp':
return new RegExp(variable)
case 'Set':
const set = new Set()
for (let item of variable.values()) {
set.add(deepCopy(item))
}
return set
case 'Map':
const map = new Map()
map.forEach((value, key) => {
map.set(key, deepCopy(value))
})
return map
default:
return variable
}
}

防抖和节流

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 防抖
function debounce(fn, wait) {
let timer = null;

return function (...args) {
if (timer) clearTimeout(timer)

timer = setTimeout(() => {
fn.apply(this, args);
}, wait);
};
}

// 节流 (注意点:考虑同步循环执行函数的节流)
function throttle(fn, delay) {
let timer = null
let startTime

return function (...params) {
if (!startTime) {
startTime = Date.now()
timer = setTimeout(() => {
fn.call(this, ...params)
}, delay)
}
if (Date.now() - startTime >= delay) {
clearTimeout(timer)

fn.call(this, ...params)
startTime = Date.now()

timer = setTimeout(() => {
fn.call(this, ...params)
}, delay)
}
}
}


解题

  1. 请实现 find 函数,使下列的代码调用正确

    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // 约定:
    // title数据类型为String
    // userId为主键,数据类型为Number
    var data = [
    {userId: 8, title: 'title1'},
    {userId: 11, title: 'other'},
    {userId: 15, title: null},
    {userId: 19, title: 'title2'}
    ];
    var find = function(origin) {
    // your code are here...
    }
    // 查找 data 中,符合条件的数据,并进行排序
    var result = find(data).where({
    'title': /\d$/
    }).orderBy('userId', 'desc');

    console.log(result);// [{ userId: 19, title: 'title2'}, { userId: 8, title: 'title1' }];
    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    class MyArray extends Array {
    where = filterOpt => {
    let list = this
    for (let key of Object.keys(filterOpt)) {
    list = this.filter(item => {
    return filterOpt[key].test(item[key])
    })
    }
    return list
    }

    orderBy = (orderKey, orderType) => {
    let list = this
    list = this.sort((a, b) => {
    if (orderType === 'desc') {
    return b[orderKey] - a[orderKey]
    } else {
    return a[orderKey] - b[orderKey]
    }
    })
    return list
    }
    }

    var find = function (origin) {
    return new MyArray(...origin)
    }
  2. 实现一个求和函数sum,支持任意参数: sum(1), sum(1,2,3,4); 支持连续调用: sum(1)(2)(3)。如下所示:

    javascript
    1
    2
    const result = sum(1)(2,3)(4);
    console.log(result) // 输出 10
    javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    function sum(...params) {
    let numList = params
    let res = 0

    const returnFn = (...childParams) => {
    numList.push(...childParams)
    return returnFn
    }

    // console.log会调用参数的toString方法
    returnFn.toString = () => {
    res = numList.reduce((total, item) => {
    return total + item
    })
    return res
    }

    return returnFn
    }


文章作者: 盛顺炎
文章链接: https://www.shengshunyan.xyz/2021/05/31/%E5%89%8D%E7%AB%AF%E6%89%8B%E5%86%99%E4%BB%A3%E7%A0%81%E9%A2%98/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 果实的技术分享
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论