这三个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 属性,但是不具备数组的方法,伪数组长度不可变
常见的伪数组有哪些:
- querySelectAll
- getElementsByClassName
- getElementsByName
- getElementsByTagName
- 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) // 95bind与 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,4bind,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 不一样
需求:
- 如果只有一个参数,可以执行,不报错
- 如果有两个参数,或者两个以上的参数,就必须是一个数组
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)())
最后:本人喜欢研究面试题,希望有更多志同道合的朋友一起来交流研究,可以帮助修改简历