跳至主要內容

原生方法实现

星星大约 4 分钟

原生方法实现

instance

function myInstanceOf(obj, origin) {
    if (typeof obj != 'object' || obj == null) return false
    while (obj) {
        if (obj._proto_ == origin.prototype) {
            return true
        }
        obj = obj._proto_
    }
    return false
}

New

function myNew(Fun) {
    let obj = {}
    obj._proto_ = Fun.prototype
    let res = Fun.apply(obj, Array.prototype.slice.call(arguments, 1))
    return typeof res == 'object' ? res : obj
}

call

function myCall(context, ...args) {
    context = context || window // context = (typeof context === 'object' ? context : window)
    // 防止覆盖掉原有属性
    let key = Symbol()
    // 这里的this为需要执行的方法
    context[key] = this
    let res = context[key](...args)
    delete context[key]
    return res
}

bind

function myBind(context, args) {
    context = context || window // context = (typeof context === 'object' ? context : window)

    return (...args) => {
        this.call(context, ...args)
    }
}

原型链继承

function Parent() {
    this.name = 'tom'
}
Parent.prototype.sayName = function () {
    console.log(this.name)
}
function Child() {}
Child.prototype = new Parent()

构造函数继承

function Parent(name) {
    this.name = name
    this.sayName = function () {
        console.log(this.name)
    }
}
function Child(name) {
    Parent.call(this, name)
}

组合继承

function Parent(age) {
    this.age = age
    this.name = 'tom'
}
Parent.prototype.sayName = function () {
    console.log(this.name)
}

function Child(name, age) {
    Parent.call(this, name, age)
}
Child.prototype = new Parent()
Child.prototype.constructor = Child

function deepClone(source) {
    let tar = source.constructor == Array ? [] : {}
    for (let key in source) {
        if (source[key] && source.hasOwnProperty(key)) {
            if (typeof source == 'object') {
                tar[key] = source[key].constructor == Array ? [] : {}
                tar[key] = deepClone(source[key])
            } else {
                tar[key] = source[key]
            }
        }
    }
    return tar
}

curry

function curry(fn) {
    if (fn.length < 1) return fn
    const generate = (...args) => {
        if (fn.length == args.length) {
            return fn(...args)
        } else {
            return (...arg) => {
                return generate(...args, ...arg)
            }
        }
    }
    return generate
}

EventBus

class EventBus {
    constructor() {
        this.catch = {}
    }
    on(name, fun) {
        let tasks = this.catch[name]
        if (tasks) {
            this.catch[name].push(fun)
        } else {
            this.catch[name] = [fun]
        }
    }
    off(name, fun) {
        let tasks = this.catch[name]
        if (tasks) {
            let index = tasks.findIndex(item => item.fun == fun)
            this.catch[name].splice(index, 1)
        }
    }
    emit(name, once = false, ...args) {
        if (this.catch[name]) {
            let tasks = this.catch[name].slice()
            for (let fn of tasks) {
                fn(...args)
            }
        }
        if (once) {
            delete this.catch[name]
        }
    }
}

promise.all 和 promise.race

const myPromiseAll = function (promiseList) {
    return new Promise((resolve, reject) => {
        let count = 0
        let ans = []
        for (let i = 0; i < promiseList.length; ++i) {
            promiseList[i]
                .then(res => {
                    ans[i] = res
                    count++
                    if (count == promiseList.length) {
                        resolve(ans)
                    }
                })
                .catch(err => {
                    reject(err)
                })
        }
    })
}

const myPromiseRace = function (promiseList) {
    return new Promise((resolve, reject) => {
        promiseList.forEach(item => {
            item.then(
                val => resolve(val),
                err => reject(err)
            )
        })
    })
}

Promise.prototype.all = function (promises) {
    //promises为 Array
    let result = []
    let promiseCount = 0
    let promiseLength = promises.length

    function isPromise(obj) {
        return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
    }

    return new Promise(function (resolve, reject) {
        for (let i = 0; i < promiseLength; ++i) {
            let cur = promises[i]
            if (isPromise(cur)) {
                // cur.then((res)=>{
                Promise.resolve(cur).then(
                    res => {
                        promiseCount++
                        result[i] = res
                        if ((promiseCount = promiseLength)) {
                            resolve(result)
                        }
                    },
                    err => {
                        reject(err)
                    }
                )
            } else {
                result[i] = promises[i]
                resolve(result)
            }
            s
        }
    })
}

jsonp

const myJsonp = function (url, params, callback) {
    let generate = () => {
        let str = ''
        for (let key in params) {
            if (Object.prototype.hasOwnProperty.call(params, key)) {
                str += `${key}=${params[key]}&`
            }
        }
        str += `callback=${callback}`
        return `${url}?${str}`
    }
    return new Promise((resolve, reject) => {
        let script = document.createElement('script')
        script.src = generate()
        document.body.appendChild(script)
        window[callback] = data => {
            resolve(data)
            document.removeChild(script)
        }
    })
}

ajax

const myAjax = function (url) {
    return new Promise((resolve, reject) => {
        let xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('MscroSoft.XMLHttp')
        xhr.open('GET', url, false)
        xhr.setRequestHeader('Accept', 'application/json')
        xhr.onreadystatechange = function () {
            if (xhr.readyState !== 4) return
            if (xhr.status == 200 || xhr.status == 304) {
                resolve(xhr.responseText)
            } else {
                reject(new Error(xhr.responseText))
            }
        }
        xhr.send()
    })
}

lazyload

const lazyload = function () {
    const imgs = document.getElementsByTagName('img')
    const len = imgs.length
    // 视口的高度
    const viewHeight = document.documentElement.clientHeight
    // 滚动条高度
    const scrollHeight = document.documentElement.scrollTop || document.body.scrollTop
    for (let i = 0; i < len; i++) {
        const offsetHeight = imgs[i].offsetTop
        if (offsetHeight < viewHeight + scrollHeight) {
            const src = imgs[i].dataset.src
            imgs[i].src = src
        }
    }
}

滚动加载

window.addEventListener(
    'scroll',
    function () {
        const clientHeight = document.documentElement.clientHeight
        const scrollTop = document.documentElement.scrollTop
        const scrollHeight = document.documentElement.scrollHeight
        if (clientHeight + scrollTop >= scrollHeight) {
            // 检测到滚动至页面底部,进行后续操作
            // ...
        }
    },
    false
)

深拷贝

function deepClone(tar, map = new Map()) {
    if (typeof tar == 'object') {
        let target = Array.isArray(tar) ? [] : {}
        if (map.get(tar)) {
            return map.get(tar)
        }
        map.set(tar, target)
        for (let key in tar) {
            target[key] = clone(tar[key], map)
        }
        return target
    } else {
        return tar
    }
}

防抖 节流

function debounce(event, time, flag) {
    let time = null
    return function (...args) {
        clearTimeout(time)
        if (flag && !time) {
            event.apply(this, args)
        }
        time = setTimeout(() => {
            event.apply(this, args)
        }, time)
    }
}

function throttle(event, time) {
    let timer = null
    return function (...args) {
        if (!timer) {
            timer = setTimeout(() => {
                timer = null
                event.apply(this, args)
            }, time)
        }
    }
}

localStorage 设置过期时间

export function setLocalStorageWithExpire(key, value, expire) {
    // expire单位为天
    if (isNaN(expire) || expire < 1) {
        throw new Error('有效期应为一个有效数值')
    }
    let time = expire * 86400000
    let obj = {
        data: value, //存储值
        time: Date.now(), //存值时间戳
        expire: time, //过期时间
    }
    localStorage.setItem(key, JSON.stringify(obj))
}
export function getLocalStorageWithExpire(key) {
    let val = localStorage.getItem(key)
    if (!val) return val
    val = JSON.parse(val)
    if (Date.now() > val.time + val.expire) {
        localStorage.removeItem(key)
        return
    }
    return val.data
}
// enum.ts
//字典 Dictionaries    expire过期时间key    permanent永久不过期
export enum Dictionaries {
    expire = '__expire__',
    permanent = 'permanent'
}
// type.ts
import { Dictionaries } from "../enum"
export type Key = string //key类型
export type expire = Dictionaries.permanent | number //有效期类型
export interface Data<T> {  //格式化data类型
    value: T
    [Dictionaries.expire]: Dictionaries.expire | number
}
export interface Result<T> { //返回值类型
    message: string,
    value: T | null
}
export interface StorageCls { //class方法约束
    set: <T>(key: Key, value: T, expire: expire) => void
    get: <T>(key: Key) => Result<T | null>
    remove: (key: Key) => void
    clear: () => void
}

// index.ts
import { StorageCls, Key, expire, Data,Result } from "./type";
import { Dictionaries } from "./enum";
export class Storage implements StorageCls {
    //存储接受 key value 和过期时间 默认永久
    public set<T = any>(key: Key, value: T, expire: expire = Dictionaries.permanent) {
    //格式化数据
        const data = {
            value,
            [Dictionaries.expire]: expire
        }
        //存进去
        localStorage.setItem(key, JSON.stringify(data))
    }

    public get<T = any>(key: Key):Result<T | null> {
        const value = localStorage.getItem(key)
        //读出来的数据是否有效
        if (value) {
            const obj: Data<T> = JSON.parse(value)
            const now = new Date().getTime()
            //有效并且是数字类型 并且过期了 进行删除和提示
            if (typeof obj[Dictionaries.expire] == 'number' && obj[Dictionaries.expire] < now) {
                  this.remove(key)
                  return {
                     message:`您的${key}已过期`,
                     value:null
                  }
            }else{
            //否则成功返回
                return {
                    message:"成功读取",
                    value:obj.value
                }
            }
        } else {
           //否则key值无效
            console.warn('key值无效')
            return {
                message:`key值无效`,
                value:null
             }
        }
    }
    //删除某一项
    public remove(key:Key) {
        localStorage.removeItem(key)
    }
    //清空所有值
    public clear() {
       localStorage.clear()
    }
}



取对象深度嵌套的属性

/**
 * 安全读取对象深度嵌套的属性,遇到不存在的属性会返回 undefined,避免报错
 *
 * @param   {object}    target  目标对象
 * @param   {string}    path    属性路径,为点语法组成的字符串,支持字面量,可以使用模板字符串支持变量
 * @return  {any}               返回对象的属性值
 * @用例    getProp(obj, 'a.b.c') => obj.a.b.c
 * @用例    getProp(obj, `a.${this.b}.c`) => obj.a[this.b].c
 */
export function getProp(target, path) {
    return path.split('.').reduce((obj, key) => {
        return obj && obj[key]
    }, target)
}
上次编辑于:
贡献者: wanghongjie