美文网首页
手写javascript 方法(升级)

手写javascript 方法(升级)

作者: lmmy123 | 来源:发表于2019-07-10 16:00 被阅读0次

//手写call方法
Function.prototype.mycall = function(content) {
    // 1.类型判断
    if (typeof this !== 'function') {
        throw new Error('not function')
    }
    // 2. 绑定的上下文处理,没有则默认window
    content = content || window
    // 3.最重要的一步/ 虚拟出一个fn属性,将函数(this)作为对象的方法,从而this会指向对象(content)
    content.fn = this 
    // 4. 获取参数
    let args = Array.prototype.slice.call(arguments, 1)
    // 5. 调用函数等到结果
    let result = content.fn(...args)
    // 6.删除虚拟出来的fn
    delete content.fn 
    // 7. 返回结果
    return result   
}

// 手写apply 方法
Function.prototype.myapply = function(content) {
    if(typeof this !== 'function') throw new Error('not function')

    content = content || window

    content.fn = this
    // 原理同call,只是 参数这里特殊处理, 只取第二个参数
    let arg = arguments[1]
    let reuslt = content.fn(...arg)
    delete content.fn
    return reuslt

}

/**
* 手写实现bind方法
* 返回一个新的函数,并将this指向绑定的对象
* 新的函数,可以使用new调用
*/
Function.prototype.bind = function(content) {
    if(typeof this !== 'function') throw new Error('not function')
    // 保存this(函数)   
    let self = this

    let args = [].slice.call(arguments,1)
    // 返回一个新的函数
    // 实现bound 可以使用new 调用
    let bound = function () {
        // 合并参数
        let finalArgs = args.concat([...arguments])
        // 如果this是bound的实例,即使用 new方法调用bound
        if ( this instanceof bound ) {
            // 原型继承
            if(self.prototype) {
                this.prototype = Object.create(self.prototype)
            }
            // 如果返回的不是引用类型的值,就返回this
            let result = this.apply(this, finalArgs)
            let isObject = typeof result === 'object' && result !== null
            let isFunction = typeof result === 'function'
            if(isObject || isFunction) return result
        }

        // 修改this指向,返回结果
        return self.apply(content, finalArgs)
    }   

    return bound

}

/**
*  实现 instanceof 方法
*   obj 检测的对象
*   func 构造函数
*   return boolean
* 判断 func的原型属性(func.prototype)是否在obj的原型链上
*/
function instanceof1 (obj, func) {
    let pro = obj.__proto__ 
    let pro2 = func.prototype // 原型对象
    while(true) {
        if(pro === null) return false
        if (pro === pro2) return true
            console.log(1)
        pro = pro.__proto__ // 依次向上查原型链
    }
}


// Object.create(原型对象) 生成实例,继承

function create(proto) {
    var F = function(){}
    F.prototype = proto

    return new F() 
}


/**
* 实现一个new操作符
* 1).创建一个新对象
* 2).将新对象继承传入构造器的原型对象
* 3).将this的指向指向新对象,并调用返回结果
* 4).判读结果类型,如果是对象则返回,基本类型则返回obj
*/
function new1(func) {
    let obj = {}
    // 继承
    Object.setPrototypeOf(obj, func.prototype)
    // 修改this
    let arg = [...arguments].slice(1)
    let result =  func.call(obj, arg)
    if (typeof result == 'object') return reuslt
    return obj  

}

// 实现promise
/**
* new Promise((resolve, reject)=> {
    
    resove( data )
    reject( error )
})
* then( reslove(), rejectd() )
*/

class Promise {
    constructor( func ) {
        // 声明3个状态 pending/fulfilled/rejected
        this.state = 'pending'
        // 声明 响应数据和失败原因
        this.resdata = null
        this.rejectreson = null

        // 声明内部的两个方法
        let resolve = res => {
            if (this.state === 'pending') {
                this.state = 'fulfilled'
                this.resdata = res
            }
        }

        let reject = err=> {
            if(this.state === 'pending') {
                this.state = 'rejected'
                this.rejectreson = err

            }
        }

        //自动执行函数
        try {
            func(resolve, reject)
        }catch (e){
            reject(e)
        }
    }

    then (onfulfilled, onrejected) {
        swith( this.state ) {
            case 'fulfilled':
                onfulfilled(this.resdata)
            break;
            case 'rejected':
                onrejected(this.rejectreson)
            break;
            default:    

        }
    }
}


//浅拷贝 —— 一层拷贝
Object.assign({})
{...obj}


// 深度拷贝
var obj = { name: {age: [12,3]} }

function deepCopy (obj) {
    if (typeof obj !== 'object' || obj === null) return obj

    let result = Array.isArray(obj) ? [] : {}
    for(let key in obj) {
        if ( obj.hasOwnProperty(key) ) {
            result[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]
        }

    }
    return result
}

// 使用setTimeout 模拟 setinterval

let timer = function ( cb, i ) {
    cb()
    setTimeout(timer, i)
}

// 继承1
// 构造器中 使用 superClass.apply(this, args)
// subClass 子类
// superClass 父类
var jc = function (superClass, subClass) {
    var prototype = Object.create(superClass.prototype)
    subClass.prototype = prototype
    prototype.constructor = subClass    
}
// 继承2
var jc2 = function (superClass, subClass) {
    var F = function() {}
    F.prototype = superClass.prototype
    subClass.prototype = new F()
    subClass.prototype.constructor = subClass
}

//实现一个基本的event bus
/** 构造函数
const bus = new Bus()
* on(type, fn)
* emit(type, data)
* ps: on是监听事件,添加事件,emit才是触发事件
*/

class Bus {
    constructor () {
        this.hashMap = new Map()    
    }
    // 发送事件触发事件
    emit (type, data) {
        let handle = this.hashMap.get(type)
        handle.call(this, data)
    }

    // 监听事件
    on (type, fn) {
        if(!this.hashMap.get(type)) {
            this.hashMap.set(type, fn)
        }
    }
}

/**
/** 实现一个双向绑定
*   
*  data ={ val: '' }
*  <input onInput={}  value=data.val/>
*/
*/

function model () {
    val data = {}
    var input = document.getElementById('input')
    input.addEventListener('input', function(e){
        data.val = e.target.value
    })

    Object.defineProperty(data, 'val', {
        enumrable: true,
        configurable: true,
        set: function(val, preval) {
            if( val === preval) return
            input.value = val   
        },  
        get: function(){
            return data.value
        }
    })
}

/**
* /** 简单路由
*   hash路由
*/
*/

class Route {

    constructor() {
        this.routes = []
        this.currentHash = ''

        this.freshRoute = this.freshRoute.bind(this)

        window.addEventListener('load', this.freshRoute, false)
        window.addEventListener('hashchange', this.freshRoute, false)

    }
    //存储
    pushStore(path, cb) {
        this.routes[path] = cb
    } 

    // 更新
    freshRoute () {
        this.currentHash = location.hash.slice(1) || '/'
        this.routes[this.currentHash]()
    }
}



/**
* 手写ajax
*/

function ajax () {

    //1.创建ajax对象
    let xhr = new XMlHttpRequest()
    //2. 打开链接
    xhr.open(method, url, async)
    //3 发送
    xhr.send(data)
    //4 接受处理

    xhr.onreadystatechange = function(res) {
        if (xhr.readyStatus === 4 && xhr.status === 200) {
            console.log(xhr.responseText)
        }
    }
}

/**
* /**懒加载
* data-src
* img.offsetTop - document.documentElement.scrollTop < document.documentElement.clientHeight
* 遍历 满足条件 赋值src scroll
*/
var n = 0 // 避免重复从第一张图开始
function lazyLoad () {
    var imgs = document.getElementbyTagName('img')
    // 可视去高度
    var clientHeight = document.documentElement.clientHeight || document.body.clientHeight

    // 滚动高度
    var srcollTop = document.documentElement.scrollTop || document.body.scrollTop
    for (var i =n;i<imgs.length;i++) {

        if ( img[i].offsetTop - scrollTop < clientHeight ) {
            if(img[i].getAttribute('src') == '') {
                img[i].src = img[i].getAttribute('data-src')
            }
            n = i + 1
        }
    }

}
window.addEventListener('scroll', lazyLoad)


/**
*  防抖 闭包保留 timer 定时器标志
* 在规定时间内,触发事件后,会重新计算延时时间
*/
function debounce(fn, delay) {
    
    let timer = null

    return function() {
        var content = this
                var arg = arguments
        clearTimeout(timer)
        timer = setTimeout(function(){
            fn.call(this, ...arg)
        }, delay)
    }
}

/**
节流, 在规定时间内,多次粗发,只执行一次
*/
function throote (fn, s){
    var timer = null
    return function () {
        var content = this
                 var arg = arguments
        if(timer) return
        timer = setTimeout(function(){
            fn.call(content, ...arg)
            timer = null
        }, s)

    }   

}

// 利用闭包 包时间
function throte2(fn, s) {
    var prevnow = +new Date()
    
    return function() {
        var content = this
                var arg = arguments
        let now = +new Date()
        if(now - prevnow >= s) {
            fn.apply(content, arg)
            prevnow = +new Date()
        }

    }

}

//偏函数 将接收多个参数的函数变为接收一个参数,并接受剩余参数的新函数
function partial(fn) {
    var conetnt = this
    var args = [...arguments].slice(1)
    return function(){
        var finalargs = args.concat([...arguments])
        fn.apply(conetnt, finalargs)
    }       
}

// 函数柯里化,将多参数函数变成接收单参的新函数
// fn(1,2,3,4) =>>> fnn(1)(2)(3)(4)
// 结合参数长度来判读是执行递归还是执行函数
function curry(fn) {
  const firstargs = [].slice.call(arguments, 1)
  return function() {
     var args = [].slice.call(arguments)
    if(firstargs){
        args =   firstargs.concat(...args)    
    }
   
     if( args.length < fn.length ){
      //实参小于新参数,则递归
      return curry.call(this, fn, ...args)
    }else{
      return fn.apply(this, args)
    }
  }
}
// 调用
function fn(a,b,c,d) {console.log(a+b+c+d)}
var curfn = curry(fn)
curfn(1)(2)(3)(4) // 10

/**
* 实现一个json.stringify
* Boolean|Number|string 类型会自动转换为原始值
* undefined,函数以及symbol, 会被忽略
* 不可枚举的属性会被忽略
* 如果属性指向自身,即循环引用,属性会被忽略
*/
function josnStringify(obj) {
    let type  = typeof obj

    if(type !== 'object' || type === null) {
        if(/string|undefined|function/.test(type)) {
            obj = '"' + obj + '"'  
        }
        return String(obj)

    }else {
        let json = []
        arr = (obj && obj.constructor === Array)
        for(let k in obj) {
            let v = obj[k]
            let type = typeof v
            if(/string|undefined|function/.test(type)) {
                v = '"' + v + '"'
            }else if(typeof === 'object') {
                v = josnStringify(v) // 递归
            }
            // **
            json.push((arr ? "" : '"' + k + '":') + String(v))
        }
        // 返回
        return (arr ? '[' : '{') + String(json) + (arr ? ']' : '}')
    }
}

/** 实现一个 json.parse
* eval('('+arg+')') ,不建议使用,会有安全隐患
* 第二种方式: new Function()
*/
var jsonStr = '{"age": 20, "name": "jack"}'
var json = (new Function('return ' + jsonStr))()









相关文章

网友评论

      本文标题:手写javascript 方法(升级)

      本文链接:https://www.haomeiwen.com/subject/gnvhkctx.html