常用函数的JavaScript实现

转载自奇舞周刊微信公众号,https://mp.weixin.qq.com/s/YQlJ2Ey7Ha9hcs_BkvrB3w
看完觉得还不够,手动敲一敲加深记忆………

节流和防抖

节流和防抖是前端的一个高频面试题,概念糊弄不清的话面试中很容易出错。

节流和防抖的作用都是防止函数多次调用。区别在于,假设用户一直触发这个函数,防抖的作用是如果函数触发间隔小于wait,防抖的情况只会调用一次函数,而节流的情况是每隔一定时间wait,调用一次函数。

节流的简单实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function throttle(fn, threshhold) {
var last, timerId;
threshhold || (threshhold = 250)

return function() {
var now = Date.now()
if (last && now - last < threshhold) {
clearTimeout(timerId)
timerId = setTimeout(() => {
fn.apply(this, arguments)
}, threshhold)
} else {
last = now
fn.apply(this, arguments)
}
}
}

防抖的简单实现:

1
2
3
4
5
6
7
8
9
10
function debounce(fn, inteval) {
var timerId = null

return function() {
clearTimeout(timerId)
timerId = setTimeout(() => {
fn.apply(this, arguments)
}, inteval)
}
}

Call, apply, bind 的js实现

call,apply是JavaScript中很重要的概念,也是面试中的高频考点。不光是要了解其特点、用法,还要理解他们是怎么实现的。

  • call的简单实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Function.prototype.call = function(cxt, ...args) {
ctx || (ctx = window)
// 将函数设为对象的属性
ctx.fn = this

let args = []
// 执行函数
let r = eval(`ctx.fn(${args})`)

// 删除函数
delete ctx.fn

return r
}
  • apply的简单实现
1
2
3
4
5
6
7
8
9
Function.prototype.apply = function(ctx, args) {
ctx || (ctx = window)
ctx.fn = this

let r = eval(`ctx.fn(${args})`)
delete ctx.fn

return r
}

关于call,apply的模拟实现更细节的讲解可以查看 https://github.com/mqyqingfeng/Blog/issues/11

  • bind的简单实现
1
2
3
4
5
6
7
8
9
10
11
Function.prototype.bind = function(obj) {
if (typeof this !== 'function') {
return;
}

var _self = this
var args = [].slice.call(arguments, 1)
return function() {
return _self.apply(obj, args,concat([].slice.call(arguments)))
}
}

关于call,apply,bind方法的详细介绍参考这篇文章https://mp.weixin.qq.com/s/DlUJq0JJzHjnPwCI_SAI5Q

new的实现

new做了什么:

  1. 创建一个全新的对象。
  2. 这个对象会被执行[[prototype]](也就是proto)链接。
  3. 生成的新对象对绑定到函数调用的this
  4. 通过new创建的每个对象将最终被[[prototype]]链接到这个函数的prototype对象上。
  5. 如果函数没有返回对象类型object(包含function,array,date,regexg,error),那么new表达式中的函数调用会自定返回这个新的对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function newOps(ctor) {
if (typeof ctor !== 'function') {
throw new Error('the first param must be a function')
}

const newObj = Object.create(ctor.prototype)
const args = [].slice.call(arguments, 1)

const ctorReturnResult = ctor.apply(newObj, args)

if ((typeof ctorReturnResult === 'object' && typeof ctorReturnResult !== null) || typeof ctorReturnResult === 'function') {
return ctorReturnResult
}
return newObj
}

函数柯里化

1
2
3
4
5
6
7
8
9
10
11
function currying(fn) {
const argArr = []
let closure = function(...args) {
if(args.length > 0) {
argArr = [...argArr, ...args]
return closure
}
return fn(...argArr)
}
return closure
}

斐波拉切数列

  • R1

    1
    2
    3
    4
    5
    6
    function fib(n) {
    if (n===0 || n===1) {
    return n
    }
    return fib(n-2) + fib(n-1)
    }
  • R2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function Fibonacci(n) {
    if(n<=1) {
    return n;
    } else{
    var f0=0;f1=1
    for(var i=2;i<=n;i++) {
    f2=f0+f1;
    f0=f1;
    f1=f2;
    }
    return f2;
    }
    }