bind,apply,call的高级面试题

347 阅读2分钟
这三个api都是改变this的指向问题, 在前端开发过程中,会经常使用到这三个api,那么需要我们非常清楚,这三个之间的区别,话不多说,代码实现

call,apply的区别

这两个 api 非常相似,只是在传递参数上的细微区别

let person1 = {
    name:"张三",
    age:19,
    say(...arg){
        console.log(`姓名是:${this.name},年龄是:${this.age},参数:${arg}`)
    }
}

let person2 = {
    name:"李四",
    age:23
}

person1.say.call(person2,1,2,3,4) // 姓名是:李四,年龄是:23,参数:1,2,3,4
person1.say.apply(person2,[1,2,3,4]) // 姓名是:李四,年龄是:23,参数:1,2,3,4

常见面试题

1、如何将伪数组变为真数组

什么叫伪数组,哪些是属于伪数组?

特点:具备 length 属性,但是不具备数组的方法,伪数组长度不可变

常见的伪数组有哪些:

  1. querySelectAll
  2. getElementsByClassName
  3. getElementsByName
  4. getElementsByTagName
  5. argument

这些 API 获得的集合叫做伪数组

let person1 = {
    name:"张三",
    age:19,
    say(){
        console.log(`姓名是:${this.name},年龄是:${this.age}`)
        console.log(arguments)
        //  当我们对 arguments 使用数组的方法的时候,就会出现报错
        arguments.push(8)
        console.log(arguments)
    } 
}
let person2 = {
    name:"李四",
    age:23
}person1.say.call(person2,1,2,3,4)


进行改进:


let person1 = {
    name:"张三",
    age:19,
    say(){
        console.log(`姓名是:${this.name},年龄是:${this.age}`)
        let arr = Array.slice.call(arguments) 
        arr .push(8)
console.log(arguments)
    }    
}
let person2 = {
    name:"李四",
    age:23
}
person1.say.call(person2,1,2,3,4)



2、怎么无侵入数组求最大值


这一道面试题也是在考验call,apply的用法,无侵入,就是不对数组的进操作,但是拿到最大值


let arr = [1,4,6,88,34,7,9,23,95]
// 方法有两个
let res1 = Math.max.apply(null,arr) // 95
let res1 = Math.max.call(null,...arr) // 95


bind与 call,apply的区别

bind 的区别就是在改变 this 的指向的时候,并不会调用这个方法


let person1 = {
    name:"张三",
    age:19,
    say(...arg){
        console.log(`姓名是:${this.name},年龄是:${this.age},参数:${arg}`)
    }
    let person2 = {
    name:"李四",
    age:23
}
person1.say.bind(person2,1,2,3,4) // 没有任何打印
person1.say.bind(person2,1,2,3,4)() // 姓名是:李四,年龄是:23,参数:1,2,3,4


bind,call,apply的手动封装

本人的封装可能不够严谨,不会对传递的类型参数进行严密的判断,只针对核心代码的实现


1、call 的封装

Function.prototype.myCall = function(obj,...args){
    // 兼容处理
    obj = obj || window
    // 设置一个值
    const key  = Symbol()
    obj[key] = this
    // 执行函数并且传参数
    obj[key](...args)
    // 手动销毁变量
    delete obj[key]
}
// 测试一下
let person = {    
        name:'张三',    
        age:18,    
        say(){        
            console.log(this.name,this.age)    
        }
    }
    let p1 = {    
          name:"李四",    
          age:89,
    }
    person.say.myCall(p1,1,2,3,4)


2、apply 的封装

要求:跟原声的 apply 不一样

需求:

  1. 如果只有一个参数,可以执行,不报错
  2. 如果有两个参数,或者两个以上的参数,就必须是一个数组

Function.prototype.myApply = function(){    
        let obj = arguments[0] || window    
        const args = arguments[1]    
        const key  = Symbol()    
        obj[key] = this    
        if(args){
        // 如果是数组        
            if(Array.isArray(args)){            
                obj[key](...args)       
            // 如果只有一个参数        
            }else if(arguments.length === 2){            
                obj[key](args)
             // 有2个以上参数,必须是数组        
            }else{            
                console.error('MyApply传递多个参数的时候,第二个参数必须是数组')        
            }    
        }else{        
            obj[key]()    
        }
        delete obj[key]
    }
    let person = {    
            name:'张三',    
            age:18,    
            say(){
                console.log(arguments)        
                console.log(this.name,this.age)    
            }
    }
    let p1 = {    
        name:"李四",    
        age:89
     }
    person.say.myApply(p1,[1,2])
    person.say.myApply(p1,1)
    person.say.myApply(p1,1,2)



3、bind 的封装

Function.prototype.myBind = function(obj,...args){    
        let self = this
        // 返回一个函数,手动调用    
        return function(){        
            let newArge = args.concat(...arguments)        
            self.myCall(obj,newArge)    
        }
}
let person = {    
        name:'张三',    
        age:18,    
        say(){       
            console.log(arguments)         
            console.log(this.name,this.age)    
        }
}
let p1 = {    
    name:"李四",    
    age:89
}
console.log(person.say.myBind(p1,1,2,3)())


最后:本人喜欢研究面试题,希望有更多志同道合的朋友一起来交流研究,可以帮助修改简历