手写javascript 方法(升级)


//手写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))()









最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343