1、call、apply、bind

实现步骤:

  1. 将函数设为对象的属性
  2. 执行该函数
  3. 删除该函数

    call

  4. call 会立即调用函数

  5. 第一个参数是指定对象,后面的都是传入的参数
  6. 如果第一个参数传入 undefined、null 会指向window ```javascript Function.prototype.myCall = function (thisArg, …args) { const fn = this

    thisArg = thisArg !== undefined && thisArg !== null ? Object(thisArg) : window

    thisArg.fn = fn const result = thisArg.fn(…args) delete thisArg.fn

    return result }

// 测试 function sum(num1, num2) { console.log(this) return num1 + num2 }

const res = sum.myCall(‘123’, 20, 30) console.log(res)

  1. <a name="fakof"></a>
  2. ## apply
  3. 1. apply 会立即调用函数
  4. 2. 第一个参数是指定对象,传参是以数组的方式
  5. 3. 如果第一个参数传入 undefined、null 会指向window
  6. ```javascript
  7. Function.prototype.myApply = function (thisArg, arrArg) {
  8. const fn = this
  9. thisArg = (thisArg !== undefined && thisArg != null) ? Object(thisArg) : window
  10. thisArg.fn = fn
  11. arrArg = arrArg || []
  12. const res = thisArg.fn(...arrArg)
  13. delete thisArg.fn
  14. return res
  15. }
  16. // 测试
  17. function sum(num1, num2) {
  18. return num1 + num2
  19. }
  20. const res = sum.myApply("123", [20, 30])
  21. console.log(res);

bind

  1. 不会立即调用函数,会返回一个变更后的函数
  2. 第一个参数是指定对象,后面的都是传入的参数
  3. 如果第一个参数传入 undefined、null 会指向window
  4. 可以分开传参,const foo = bind(this,1,2);foo(3,4) ```javascript Function.prototype.myBind = function (thisArg, …arrArgs) { const fn = this thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window

    function proxyFn(…args) {

    1. thisArg.fn = fn
    2. const res = thisArg.fn(...arrArgs, ...args)
    3. delete thisArg.fn
    4. return res

    }

    return proxyFn

}

// 测试 function foo(num1, num2) { console.log(this); console.log(num1, num2); return num1 + num2 }

// foo.myBind(“123”, 10, 20)

const bar = foo.myBind(“123”, 10, 20) console.log(bar());

  1. <a name="GP9Yo"></a>
  2. # 2、防抖、节流
  3. <a name="IAtF1"></a>
  4. ## 防抖
  5. 防抖:事件频繁触发后的n秒内只执行一次,若n秒内再次执行则重新计时
  6. ```javascript
  7. function debounce(fn, delay) {
  8. let timer = null
  9. return function (...args) {
  10. if (timer) clearTimeout(timer)
  11. timer = setTimeout(() => {
  12. fn.apply(this, args)
  13. timer = null
  14. }, delay)
  15. }
  16. }

节流

节流:事件频繁触发的过程中,在n秒内只触发一次,不管n秒内触发多少次

  1. //定时器
  2. function throttle(fn, delay) {
  3. let timer = null
  4. return function (...args) {
  5. if (timer) return
  6. timer = setTimeout(() => {
  7. fn.apply(this, args)
  8. timer = null
  9. }, delay)
  10. }
  11. }
  12. // 时间戳
  13. function throttle(fn, delay) {
  14. let last = 0
  15. return function (...args) {
  16. const now = Date.now()
  17. if (now - last > delay) {
  18. last = now
  19. fn.apply(this, args)
  20. }
  21. }
  22. }

3、instanceof

instanceof:判断其构造函数的prototype属性是否在该实例对象的原型链上

  1. function myInstanceof(target, origin) {
  2. if(target === null || (typeof target !== 'object' && typeof target !== 'function')) {
  3. return false
  4. }
  5. if(typeof origin !== 'funtion') throw new Error('origin typeError')
  6. let proto = Object.getPrototypeOf(target) // proto = target.__proto__
  7. while (proto) {
  8. if (proto === origin.prototype) return true
  9. proto = Object.getPrototypeOf(proto)
  10. }
  11. return false
  12. }

4、new

new执行过程

  • 创建一个新对象
  • 将这个对象的原型proto指向构造函数的原型对象prototype
  • 构造函数的this指向这个对象,并执行构造函数中的代码
  • 返回新对象(判断构造函数的返回值:如果返回值是对象则返回这个对象,否则返回这个新对象)
    1. function Foo(){
    2. const obj = {}
    3. obj.__proto__ = Foo.prototype
    4. const res = Foo.call(obj)
    5. return typeof res === 'object' ? res : obj
    6. }

    5、去重

    set

    1. function unique(arr){
    2. return [...new Set(arr)]
    3. }

    filter

    1. function unique(arr){
    2. return arr.filter((item, index, arr) => {
    3. return arr.indexOf(item) === index
    4. })
    5. }

    6、reduce

    1. Array.prototype.myReduce = function(cb, initValue){
    2. const arr = this
    3. let total = initValue || arr[0]
    4. for(let i = initValue ? 0 : 1; i < arr.length; i++){
    5. total = cb(total, arr[i], i, arr)
    6. }
    7. return total
    8. }

    7、Object.create()

    原理:传入的对象作为新对象的原型
    1. Object.myCreate = function(obj){
    2. function Foo(){}
    3. Foo.prototype = obj
    4. return new Foo()
    5. }

    8、数组扁平化

    数组扁平化也就是数组降维

展开一层

  1. const arr = [1, 2, [3, 4, [5, 6]]]
  2. // ES6 Array.prototype.flat() 该参数为depth为降维的深度
  3. const arr1 = arr.flat() // [ 1, 2, 3, 4, [ 5, 6 ] ]
  4. // reduce+concat
  5. const arr2 = arr.reduce((acc, val) => {
  6. return acc.concat(val)
  7. }, [])
  8. // 展开运算符+concat
  9. const arr3 = [].concat(...arr)

展开多层

  1. const arr = [1, 2, [3, 4, [5, 6]]]
  2. // ES6 Array.prototype.flat()
  3. const arr4 = arr.flat(Infinity) // [ 1, 2, 3, 4, 5, 6 ]
  4. // 递归调用
  5. function flatDeep(arr, depth = 1) {
  6. return depth > 0
  7. ? arr.reduce((acc, val) => {
  8. return acc.concat(Array.isArray(val) ? flatDeep(val, depth - 1) : val)
  9. }, [])
  10. : arr.concat()
  11. }
  12. // 堆栈
  13. function flatten(arr) {
  14. const stack = [...arr]
  15. const res = []
  16. while (stack.length) {
  17. const next = stack.pop()
  18. if (Array.isArray(next)) {
  19. stack.push(...next)
  20. } else {
  21. res.push(next)
  22. }
  23. }
  24. return res.reverse()
  25. }

9、Generator自执行函数

Generator 函数的自动执行需要一种机制,即当异步操作有了结果,能够自动交回执行权

  1. 回调函数。将异步操作进行包装,暴露出回调函数,在回调函数里面交回执行权
  2. Promise 对象。将异步操作包装成 Promise 对象,用 then 方法交回执行权
  1. function run(gen){
  2. const g = gen()
  3. function next(data){
  4. const result = g.next(data)
  5. if(result.done) return
  6. if(typeof result.value.then === 'function') {
  7. result.value.then(function(data){
  8. next(data)
  9. })
  10. } else {
  11. result.value(next)
  12. }
  13. }
  14. next()
  15. }

10、深拷贝

深拷贝:拷贝对象时不会拷贝引用,修改原对象的属性不会影响拷贝对象

  1. function deepClone(target, map = new WeakMap()) {
  2. // 判断target是不是object
  3. if(typeof target !== null && typeof target !== 'object') {
  4. return target
  5. }
  6. // 解决循环引用
  7. if(map.has(target)) {
  8. return map.get(target)
  9. }
  10. // 判断是object还是array
  11. const newObject = Array.isArray(target) ? [] : {}
  12. map.set(target, newObject)
  13. for(const key in target) {
  14. newObject[key] = deepClone(target[key], map)
  15. }
  16. return newObject
  17. }

11、浅拷贝

浅拷贝:拷贝对象时会拷贝引用,修改原对象的属性会影响拷贝对象

  1. // 方式一:展开运算符
  2. const obj1 = { ...obj }
  3. // 方式二:利用Object.assign()进行浅拷贝
  4. const obj2 = Object.assign({}, obj)
  5. // 在数组中利用 Array.prototype.concat() 进行浅拷贝
  6. const arr = [].concat(arr)

12、EventBus(事件总线)

13、函数柯里化

柯里化:就是将函数内大量的逻辑分到一个个小函数中处理 柯里化优势:

  • 确保了单一职责的原则,每个函数的职责清晰明了
  • 对代码逻辑的复用,对确定的函数无需多次调用

自动柯里化:将一个普通函数,自动转化为柯里化函数

  1. function myCurrying(fn) {
  2. // 判断当前已经接收的参数的个数,与参数本身需要接收的参数是否一致
  3. // 1.当已经传入的参数 大于等于 需要的参数时,就执行函数
  4. return function curried(...args) {
  5. if (args.length >= fn.length) {
  6. // 用apply的原因是防止在外界显示绑定了对象,与外界保持一致
  7. return fn.apply(this, args)
  8. } else {
  9. // 没有达到个数时,需要返回一个新的函数,继续接收所需参数
  10. return function (...args2) {
  11. // 接收到参数时 递归调用 继续判断参数是否满足
  12. return curried.apply(this, [...args, ...args2])
  13. }
  14. }
  15. }
  16. }

14、组合函数

15、实现继承

16、排序算法

快速排序

  1. function quickSort(arr, L, R) {
  2. if(L > R) return
  3. let left = L, right = R
  4. let point = arr[left]
  5. while(left < right) {
  6. while(left < right && arr[right] >= point) {
  7. right--
  8. }
  9. if(left < right) {
  10. arr[left] = arr[right]
  11. }
  12. while(left < right && arr[left] <= point) {
  13. left++
  14. }
  15. if(left < right) {
  16. arr[right] = arr[left]
  17. }
  18. if(left >= right) {
  19. arr[left] = point
  20. }
  21. quickSort(arr, L, left-1)
  22. quickSort(arr, left+1, R)
  23. }
  24. }