手写代码篇

217 阅读4分钟

应用型原型方法

防抖

防抖 debounce

function debounce (func, delay) {
    let timeout
    return function () {
       clearnInterval(timeout)
        timeout = setInterval(() => {
            func.apply(this, arguments)
        }, delay)
    }
 
}

节流函数

throttle, 多次调用,只调用一次

function throttle (fuc, delay) {
    let isRun = false
    return function () {
        if (isRun) {
            return
        }
        isRun = true
         setTimeout(() => {
        func.apply(this, arguments)
        isRun = false // 定时器到时间之后,会把开关打开,我们的函数就会被执行
      }, delay)
    }
}

数组去重

es5实现

function unique () {
    const res = arr.filter((item, index, array) => array.indexOf(item) = index
    return res
}

es6实现

let unique = arr => [...new Set(arr)]

数组扁平化

es5实现:

1. 递归实现
​
function flatten (arr) {
    let result = [];
    arr.forEach(item => {
       if (Array.isArray(item)) {
           result = result.concat(flatten(item))
       } else {
           result.push(item)
       }
        return result
    })
}
​
2. reduce 加递归
function flatten1 (arr) {
    return arr.reduce((res, next) => {
        return res.concat(Array.isArray(next) ? flatten1(next) : next)
    }, [])
}
​
function faltten2 (arr) {
    while(arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr)
    }
    return arr
}

es6 实现:

1.[1, [2, [3]]].flat(2)  // [1, 2, 3]

事件发布订阅

class EventEmitter {
   constructor () {
       this.cache = {}
   }
    on (name, fn) {
       if (this.cache[name]) {
           this.cache[name].push(fn)
       } else {
           this.cache[name] = [fn]
       }
    }
    
    off (name, fn) {
       let tasks = this.cache[name]
       if (tasks) {
           const index = tasks.findIndex(f => f === fn || fn.callback === fn)
           if (index >= 0) {
               tasks.splice(index,1)
           }
       }
    }
    emit(name, once = false, ...args) {
        if (this.cache[name]) {
            let tasks = this.cache[name].slice()
        }
        
          for (let fn of tasks) {
                fn(...args)
            }
            if (once) {
                delete this.cache[name]
            }
    }
}

字符串模板

function render(template, data) {
    const reg = /{{(\w+)}}/; // 模板字符串正则
    if (reg.test(template)) { // 判断模板里是否有模板字符串
        const name = reg.exec(template)[1]; // 查找当前模板里第一个模板字符串的字段
        template = template.replace(reg, data[name]); // 将第一个模板字符串渲染
        return render(template, data); // 递归的渲染并返回渲染后的结构
    }
    return template; // 如果模板没有模板字符串直接返回
}
​
let template = '我是{{name}},年龄{{age}},性别{{sex}}';
let person = {
    name: '布兰',
    age: 12
}
render(template, person); // 我是布兰,年龄12,性别undefined

对象深拷贝和浅拷贝

浅拷贝

浅拷贝时创建一个对象, 这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是 基本类型的值。如果属性是引用类型,拷贝的就是内存地址,如果其中一个对象改变了这个地址,就会影响到另一个对象。

常见的浅拷贝方式

  • Object.assign
  • es6 展开符
  • contact 数组的一个克隆方式
  • slice 数组克隆

常见的深拷贝方式

  • JSON.parse(JSON.stringfy()) 局限性(处理后正则变成了空对象, 函数变成了null)

    1.如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式,而不是对象的形式

    2.如果obj里有RegExp(正则表达式的缩写)、Error对象,则序列化的结果将只得到空对象;

    3、如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;

    4、如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null

    5、JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;

    6、如果对象中存在循环引用的情况也无法正确实现深拷贝;

  • 函数库 loash的_.cloneDeep

  • Jquery.extend

  • 手写递归函数

       // 手写深拷贝函数
             function deepClone(obj) {
                
                
                if (obj === null) return obj
    ​
                if (obj instanceof Date) return new Date(obj) // 重新拷贝
    ​
                if (obj instanceof RegExp) return new RegExp()
    ​
                if (typeof obj !== "object") return obj
                 
                const targetclone = Array.isArray(obj)? []:{}
                for(let prop in target) {
                    if(target.hasOwnProperty(prop)) {
                        targetclone[prop] = (typeof target[prop] === 'object')?
                        deepClone(target[prop]):target[prop]
                    }
                }
    ​
                return targetclone
             }
    

深拷贝

深拷贝是将一个对象从内存中完整的拷贝一份出来。 从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。浅拷贝共享一块内存, 深拷贝与原对象共享一块内存空间

         // 手写深拷贝函数
         function deepClone(obj) {
            
            
            if (obj === null) return obj

            if (obj instanceof Date) return new Date(obj) // 重新拷贝

            if (obj instanceof RegExp) return new RegExp()

            if (typeof obj !== "object") return obj
             
            const targetclone = Array.isArray(obj)? []:{}
            for(let prop in target) {
                if(target.hasOwnProperty(prop)) {
                    targetclone[prop] = (typeof target[prop] === 'object')?
                    deepClone(target[prop]):target[prop]
                }
            }

            return targetclone
         }

手写ajax

function ajax (method, url) {
   let xmlhttp
   if (window.XMLHttpRequest) {
       xmlhttp = new XMLHttpRequest() 
   } else {
       xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")
   }
    
    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200 ) {
            console.log(xml.responseText)
        }
    }
    
    xmlhttp.open(method, url, true)
    xmlhttp.send()
}

函数柯里化

函数柯里化概念: 柯里化(Currying)是把接受多个参数的函数转变为接受一个单一参数的函数,并且返回接受余下的参数且返回结果的新函数的技术。

function add () {
  console.log(arguments)
  let args = Array.prototype.slice.call(arguments)
}


// add(1,2)(12,23)(12)

数组原型方法

原型链方法

call

Function.prototype._call = function (context, ...args)  {
   let context = context || window; // 不传this则指向window
   const key = Symbol()
   context[key] = this
   const result = context[key](...args)
    //删除添加的属性
    delete context[key]
    //返回函数调用的返回值
    return result
}

Funtion.rptotype._myCall = function (context){
   if (typeof this !== "function") {
       console.error("type error")
   }
   let args = [...arguments].slice(1)
   let result = null
   
   context = context || window
   
   const key = symbol()
   
   context[key] = this
   
    result = context[key](...args)
    
    delete context[key]
    return result
}

apply

Function.prototype._apply = function (context, args) {
   let context = context || window; // 不传this则指向window
   const key = Symbol()
   context[key] = this
   const result = context[key](...args)
    //删除添加的属性
    delete context[key]
    //返回函数调用的返回值
    return result
}

Function.prototype.MyApplay = function (context) {
   if (typeof this !== "function") {
       console.error("type error")
   } 
    
    let result = null
    
    context = context || windows
    
    const key = symbol()
    
    context[key] = this
    
    if (arguments[1]) {
        result = context[key](...argments[1])
    } else {
        result = context[key]()
    }
    
    delete context[key]
    return result
}

bind

Function.prototype._bind = function (context, ...args) {
    let fn = this
    let args = args ? args : []
    return function NewFn (...newFnArgs) {
         if (this instanceof newFn) {
            return new fn(...args, ...newFnArgs)
        }
        return fn.apply(context, [...args,...newFnArgs])
    }
}

异步编程

继承