JS常见的手写问题

一、new操作符

new操作符被用来创建一个构造函数的实例对象或者生成一个类的实例,其具体进行的操作如下:

  • 创建一个空对象
  • 更改this的指向,将创建的对象的原型指向构造函数的原型
  • 调用构造函数
  • 返回结果: 当构造函数的返回值是引用类型时返回该引用类型值,否则返回创建的对象

了解了操作以后,我们具体来实现一下:

/**
 *
 * @param fn:构造函数或者类
 * @param args:构造函数的参数
 * @returns {{}|void}:当原构造函数返回的是引用值时返回引用值,否则返回该构造函数或者类的实例
 */
function myNew(fn,...args) {
    const obj = {}
    obj.__proto__ = fn.prototype
    // 更改this的指向,调用构造函数实例化该对象
    const res = fn.myCall(obj,...args)
    return typeof res !== 'Object' ? obj : res
}

function Person(name,age) {
    this.name = name
    this.age = age
}
const p1 = myNew(Person,'libai',18)
console.log(p1) //Person { name: 'libai', age: 18 }

二、更改this的指向(call,apply,bind)

手写call

call方法的作用主要是更改函数内部的this指向,接受两个参数,一个是要更改的this的指向,另一个是不定长的数组,那么我们实现以下这个函数:

  • 首先我们明白,函数内部的this指向除箭头函数外,一般都是谁调用指向谁,另外call函数的第一个参数是要指向的this对象,是对象就可以添加属性,
  • 然后呢,我们将调用call的函数赋值给要指向的this对象,
  • 最后执行函数就可以了
/**
 *
 * @param thisArg:要改变的this指向参数
 * @param args: 执行原函数需要的参数
 */
function myCall(thisArg,...args) {
    const key = Symbol('key')
    thisArg[key] = this
    thisArg[key](...args)
    delete thisArg[key]
}
Function.prototype.myCall = myCall
const name = 'window'
const obj = {
    name:'aa',
    num:2,
    eat:function (){
        console.log(this.name)
    },
    sum(num1){
        console.log(this.num + 5)
    }
}
const obj2 = {
    name:'obj2',
    num:10
}
console.log(obj.eat()) //‘aa’
console.log(obj.eat.myCall(obj2)) //‘obj2’

手写apply

实现apply的方法与call类似,只不过apply的第二个参数是数组,要求将要执行函数的参数都放进数组里,简单实现如下:

/**
 *
 * @param thisArg: 要传递的this参数
 * @param args: 参数列表
 */
function myApply(thisArg,args = []) {
    const key = Symbol('key')
    thisArg[key] = this
    thisArg[key](args)
    delete thisArg[key]
}
Function.prototype.myApply = myApply
console.log(obj.sum(10)) // 7
console.log(obj.sum.myApply(obj2,[16]))// 15

手写Bind

bind 的返回值是一个更改this之后的函数,需要手动调用。实现思路类似,简单手写如下:

/**
 *
 * @param thisArg;要传递的this的指向
 * @param args:参数列表
 * @returns {function(...[*]): *}返回的新函数
 */
function myBind(thisArg,...args){
    const key = Symbol('key')
    thisArg[key] = this
    return function (...newArgs) {
       return thisArg[key](...args,...newArgs)
    }
}
Function.prototype.myBind = myBind
console.log(obj.eat.myBind(obj2)()) // obj2
console.log(obj.sum.myBind(obj2,10)()) //15

手写debounce

防抖作为前端常见优化性能的手段,我们需要学习并理解。
防抖指的是在高频触发的事件中,多次触发但只有在最后一次触发并暂停一段时间后才会执行。
应用场景如下: input,keyup,scoll,resize等事件
现简单实现如下:

/**
 *
 * @param fn: 需要防抖优化的函数
 * @param delay: 延迟的时间,单位是ms
 * @returns {(function(...[*]): void)|*}
 */
function debounce(fn,delay) {
    let timer = null
    return function (...args) {
        const _this = this
        clearTimeout(timer)
        timer = setTimeout(() => {
            fn.apply(_this,args)
        },delay)
    }
}

先写到这里,欢迎多多指正~

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值