手写一些polyfill,总结一些手写实现

351 阅读3分钟

1.instanceof的实现

原理:按原型链进行查找。

//1.instance
function myInstanceOf(left,right){
    while(true){
        if(left.__proto__ === null){
            return false
        };
        if(left.__proto__ === right.prototype){
            return true;
        }
        left = left.__proto__
    }
}
function Parent(){};
function Son(){}
Son.prototype = new Parent()
var baby = new Son()
var arr = []
console.log(myInstanceOf(arr,Array))//true
console.log(myInstanceOf(baby,Parent))//true

2.new的实现

1.原型链;2.调用构造函数;3.返回值判断

/**
 * new的实现
 */
function myNew(father,...args){
    //1.指定原型链
    var obj = Object.create(father.prototype);
    //2.调用构造函数
    var res = father.call(obj,...args);
    //3.返回值判断
    return typeof res === "object" ? res : obj
};
function Person(name){
    this.name = name
}
var xixi = myNew(Person,"xixixi");
console.log(xixi.name)//xixixi

3.缓存函数的实现

1.闭包;2.返回一个函数去接受参数

/**
 * 缓存函数的实现
 */
function memorize(fn){
    var cache = {};
    return function(){
        let key = JSON.stringify(arguments);
        if(cache[key]){
            return cache[key];
        }else{
            var res = fn.call(null,...arguments);
            cache[key] = res;
                return res;
        }
    }
}
function add(a,b){
    console.log("开始缓存")
    return a+b
}
var add1 = memorize(add)
console.log(add1(1,2))
console.log(add1(1,2))
console.log(add1(2,2))
console.log(add1(2,2))
// 开始缓存
// 3
// 3
// 开始缓存
// 4
// 4

4.函数柯理化实现

1.返回一个函数去接受参数;2.判断参数的数目

/**
 * 4.柯理化实现
 */
function curry(fn,args){
    var len = fn.length;
    var args = args || [];
    return function(){
        var newArgs = args.concat([...arguments]);
        //参数超过len没判断,可以加一个
        if(newArgs.length < len){
            // console.log(this)
            return curry.call(this,fn,newArgs);
        }else{
            return fn(...newArgs);
        }
    }
};
function add(a, b,c,d) {
    return a + b+c+d;
}

var CAdd = curry(add);
var c = CAdd(1)(2)
console.log(c(3)(4));//10

5.call的实现

/**
 * call实现
 */
Function.prototype.myCall = function (context, ...args) {
    if (!context || context === null) {
        context = window;
    }
    // 创造唯一的key值  作为我们构造的context内部方法名
    let fn = Symbol();
    context.fn = this; //this指向调用call的函数,相当于将调用call函数的函数,赋值给context.fn,以便context的环境中稍后执行
    // 执行函数并返回结果 相当于把自身作为传入的context的方法进行调用了
    var res =  context.fn(...args);//这里用到了Es6的语法"...",call是ES3的东西
    delete context.fn//删除掉这个没用属性
    return res
};

var obj = {
    name:"zhu"
}
function foo(){
    var name = "zhao";
    console.log(this.name)
}
foo.myCall(obj)

6.apply的实现

Function.prototype.myApply = function(context,arr){
    if(!Array.isArray(arr)){
        throw new Error("传入的第二个参数必须为数组")
    };
    if(!context || context === null){
        context = window
    };
    var fn =  Symbol();
    context.fn = this;
    var res = context.fn(...arr);
    delete  context[fn]
    return res

}
var fo = {
    value: 1
};
var value = 3
function bar(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value);
}
bar.myApply(fo,['kevin', 18])
//kevin
//18
//1
/**
 * 7.bind实现
 * 1.改变this 2.返回一个绑定this的函数 3.接收参数 4.柯理化传参数
 */

Function.prototype.myBind = function (context){
    var args = [...arguments].slice(1);
    var _this = this;
    return  function(){
        var newArgs = [...arguments];
        return _this.apply(context,args.concat(...newArgs))
    }
};

let Person = {
    name: 'zhu',
    say(age) {
        console.log(this)
        console.log(`我叫${this.name}我今年${age}`)
    }
}

Person1 = {
    name: 'zhao'
}
var fn = Person.say.myBind(Person1);
fn(11)
// { name: 'zhao' }
// 我叫zhao我今年11

8.深拷贝

function deepCopy(obj){
    if(typeof obj != "object") {
        throw new Error("输入必须为对象或者数组")
    };
    var newObj = Array.isArray(arr) ?  [] : {};
    for(var index in obj) {
        if(obj.hasOwnProperty(index)){
            //hasOwnProperty忽略掉那些从原型链上继承到的属性
            if (typeof obj[index] === "object") {
                newObj[index] = deepCopy(obj[index]);
            } else {
                newObj[index] = obj[index]
            }
        }
    }
    return newObj;
}
var arr = [1,2,3,[4,5]]
Array.prototype[4] = 6
console.log(arr[4])//6
var newArr = deepCopy(arr)

console.log(newArr);//[ 1, 2, 3, [ 4, 5 ] ]
arr[3] = 4;
console.log(newArr);//[ 1, 2, 3, [ 4, 5 ] ]

9.防抖

每次触发事件清空上次事件的定时器

/**
 * 9.防抖
 */
function debounce(fn,delay){
    var timer = null;
    return function(){
        if(timer){
            clearTimeout(timer);
        }
        timer =  setTimeout(fn,delay)
    }
}

10.节流

回调触发后将lastTime进行更新

function throttle(fn,delay){
    var lastTime = 0
    return function(){
        var nowTime = Date.now()
        if(nowTime - lastTime > delay){
            fn.call(this)
            lastTime = nowTime
        }
    }
}

11.某种迭代器

function makeIterator(arr){
    var index = 0
    return {
        next: function (){
            return index >= arr.length ? {
                value:undefined,
                done:true
            }:{
                value:arr[index++],
                done:false
            }
        }
    }
};
let arr = [1,2,3,4]
const itArr = makeIterator(arr)
console.log(itArr.next())//{ value: 1, done: false }
console.log(itArr.next())//{ value: 2, done: false }
console.log(itArr.next())//{ value: 3, done: false }
console.log(itArr.next())//{ value: 4, done: false }
console.log(itArr.next())//{ value: undefined, done: true }

12.实现Object.create()

1.Object.create(p)方法创建一个新对象,使用现有的对象p来提供新创建的对象的__proto__。 2.在object()函数内部, 先创建一个临时性的构造函数, 然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例.

Object.prototype.myCreate = function(p){
    function F(){};
    F.prototype = p;
    return new F();
}
var Person = {
    name:"xixixi",
    age:18
}

var p = Object.myCreate(Person);
console.log(p.name)//xixixi
console.log(Person.isPrototypeOf(p))//true

13.setInterval的实现

使用setTimeout来实现

/**
 * 13.setInterval的实现
 * @param fn
 * @param delay
 * @param count
 */
function myInterval(fn,delay,count){
    function In(){
        if(count--){
            fn();
            setTimeout(In,delay)
        }
    }
    setTimeout(In,delay)
}
let a = () => {
    console.log(1)
}
myInterval(a,1000,5)

14.Promise.all的实现

/**
 * 14.Promise.all()的实现
 * @param p
 * @returns {Promise<unknown>}
 */
function myPromiseAll(p){
    if(Array.isArray(p) === false){
        throw new Error("传入的参数必须为一个数组");
    };
    return new Promise((resolve,reject) => {
        var result = [];
        var count = 0;
        p.forEach((promise,index) => {
            Promise.resolve(promise).then((res) => {
                result[index] = res;
                count++;
                count === p.length && resolve(result)
            },(err) => {
                reject(err)
            })
        })
    })

}
let p1 = new Promise(((resolve, reject) => {
        setTimeout(() => {
            resolve(1)
        },200)
    })),
    p2 = Promise.resolve(2),
    p3 = 3

myPromiseAll([p1, p2, p3]).then((res)=>{
    console.log(res, 'res') //[1,2,3] res
}, (err)=>{
    console.log(err, 'err')
})

15.Promise.all的变体,无论成功或者失败都输出。

/**
 * 
 * @param p
 * @returns {Promise<unknown>}
 */
Promise.myPromise_all_settled = function(p){
    if(Array.isArray(p) === false){
        throw new Error("传入的参数应该为数组");
    }
    return new Promise((resolve,reject) => {
        var result = [];
        var count = 0;
        p.forEach((promise,index) => {
            Promise.resolve(promise).then((res) => {
                count++
                result[index] = {
                    status: "fulfilled",
                    value: res
                }
                if(count === p.length){
                    resolve(result)
                }
            },(err) => {
                count++;
                result[index] = {
                    status: "rejected",
                    value: err
                };
                if(count === p.length){
                    resolve(result)
                };
            })
        })
    })
};
const p1 = Promise.resolve(1)
const p2 = new Promise((resolve) => {
    setTimeout(() => resolve(2), 1000)
})
const p3 = new Promise((resolve) => {
    setTimeout(() => resolve(3), 3000)
})

const p4 = Promise.reject('err4')
const p5 = Promise.reject('err5')
// 1. 所有的Promise都成功了
const p11 = Promise.myPromise_all_settled([ p1, p2, p3 ,p4,p5])
    .then((res) => {console.log(res)});
// 输出:[
//     { status: 'fulfilled', value: 1 },
//     { status: 'fulfilled', value: 2 },
//     { status: 'fulfilled', value: 3 },
//     { status: 'rejected', value: 'err4' },
//     { status: 'rejected', value: 'err5' }
// ]

16.eventBus实现,事件总线,发布订阅模式

/**
 * eventBus实现,事件总线,发布订阅模式
 */
class EventBus {
    constructor() {
        this.events = this.events || {};

    };
    $on(eventName, callback) {
        if (this.events[eventName]) {
            this.events[eventName].push(callback);
        } else {
            this.events[eventName] = [callback]
        }
    };
    $emit(eventName, data) {
        if (this.events[eventName]) {
            this.events[eventName].forEach((callback) => {
                callback && callback(data);
            });
        }
    };
    $off(eventName) {
        if (eventName) {
            this.events[eventName] && (delete this.events[eventName]);
        } else {
            this.events = [];
        }
    }
}
var event = new EventBus();
event.$on("resize",(args) => {
    console.log("我resized的第一个回调" + args);
})
event.$on("resize",(args) => {
    console.log("我resized的第二个回调"+args);
})
event.$emit("resize",2)
console.log(event)
// 我resized的第一个回调2
// 我resized的第二个回调2
// EventBus {
//     events: { resize: [ [Function (anonymous)], [Function (anonymous)] ] }
// }

17.实现Promise.retry(fn,time);实现超时重传

/**
 * 
 * @param PromiseFn
 * @param time
 * @returns {Promise<unknown>}
 */
Promise.retry = function(PromiseFn,time) {
    return new Promise((resolve, reject) => {
        const fn = function(){
            PromiseFn().then(res => {
                resolve(res)
            }).catch(err => {
                if(time){
                    console.log(`倒数第${time}次重试`);
                    time--;
                    fn()
                }else{
                    console.log('重试次数使用完毕,依然失败');
                    reject(err)
                }
            })
        };
        fn();
    })
};
let a = function () {
    return new Promise((res, rej) => {
        let num = Math.random() * 10;
        num < 2 ? res('数字小于5,成功') : rej('数字大于5,失败');
    })
}

Promise.retry(a, 3).then(res => {
    console.log(`res:${res}`);
}).catch(err => {
    console.log(`err:${err}`);
})

18.Array.isArray()的polyfill

Array.myIsArray = (arg) => {
    return Object.prototype.toString.call(arg) === '[object Array]'
}
console.log(Array.myIsArray([1,2,3]))