0
点赞
收藏
分享

微信扫一扫

手撕前端JavaScript(第一期)

孟佳 2022-03-11 阅读 41

1. 防抖函数(debounce)

const debounce = function(func,delay = 50){
    /*
    	func: 需要防抖的函数
    	awit: 需要等待的时间,默认为50ms
    */
    let timer = 0;	//建立一个定时器的id
    
    /* 这里面相当于一个工厂函数:
       把用户传进的func函数,加上防抖的功能;
       然后再返回
    */
    return function(...args){	// 对调用func时传入的参数进行展开
        if(timer){
            // 如果定时器存在,说明已经一次或多次触发该函数,但还未执行
            clearTimeout(timer);	// 清除定时器任务
        }
        // 无论是否存在,都再次设置定时器
        timer = setTimeout( ()=>{	
            func.apply(this,args);	// 使用apply函数,自调用函数,并将定时器id记录在timer中
        },delay);	// 设置延时
    }
}

2. 节流函数(throttle)

const throttle = function(func, unitTime=1000) {
    let lastTime = 0;	// 用于记录上一次触发的时间
    return function(...args){
        let now = +new Date();
        
        // 如果超出了设定时间范围
        if(now - lastTime > unitTime) {
            lastTime = now;		// 记录当前有效触发的触发时间
            func.apply(args);
        }
    }
}

3. 手写call()函数

// 在原型上实现
Function.prototype.myCall = function(context=window , ...args){	// (实现了第3个功能)
    let key = Symbol('key');	// 用符号创建一个唯一标识
    context[key] = this;	// 在上下文中添加新属性,这个新属性指向调用函数本身;
    
    let result = context[key](...args);	// 存储调用函数的结果 (实现了第1个功能)
    delete context[key];	// 删除属性
    return result;	// 返回调用的结果
}
function func(a,b){
    console.log(`${this.nickname}is${a+b}`);
}

let newContext = {
    nickname:'zyzc',
    color:'red'
}

func.myCall(newContext,1,2);    // zyzcis3

// 其实可以这样理解:
// 可以这样理解:
let callFunc = Symbol('key');
let newContextAfterMyCall = {
    nickname:'zyzc',
    color:'red',
    [callFunc]:(function(a,b){
        console.log(`${this.nickname}is${a+b}`);
    })
}
newContextAfterMyCall[callFunc](1,2);
delete newContextAfterMyCall[callFunc];

4. 手写apply()函数

// 在原型上实现
Function.prototype.myCall = function(context=window , ...args){	
    let key = Symbol('key');	
    context[key] = this;
    
    // 只需要在这里稍作改变就好
    let result = context[key](args);
    // 如果担心第一个参数是context会有影响,可以这样做
    // let args = [...argument].slice(1);
    
    delete context[key];	
    return result;
}

5. 手写bind()函数

Function.prototype.myBind = function(context,...outerArgs){
    let self = this;	// 存储函数调用者
    return F(...innerArgs){
        if(self instance of F){	// 如果使用new类型来创建
            return new self(...outerArgs,...innerArgs);
        }
        
        // 如果是直接调用
        return self.apply(context,[...outerArgs , ...innerArgs]);
    }
}

6. 手写instanceof

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

function myInstanceof(exmaple,classFunc){
    let proto = Object.getPrototypeOf(exmaple);
    while(true) {
        if( proto == null ) return false;	// 直到找到Object的原型null上
        
        // 判断当前
        if( proto == classFunc.prototype ) return true;		//
        
        proto = Object.getProtypeOf(proto);		// 获取proto的原型,一直顺着原型链找;
        // 也可以换成这个:proto = proto.__proto__
    }
}

7. 手写new

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。

function myNew(fn,...args){
    // 传入一个构造函数
    // 传入构造函数的参数
    
    // 创建一个新对象,这个新对象的原型 指向 fn的原型
    let instance = Object.create(fn.prototype)
    let res = fn.apply(instance,args);	// 改变this的指向
    
    // 确保返回的值是object
    return typeof res === 'object' ? res : instance;
}
举报

相关推荐

0 条评论