前言
因为最近公司招人,面试时深刻感觉到“吾生也有涯,而知也无涯”,查阅整理了一下call、apply bind的一些区别以及如何手写实现,总结一下,做个记录。
1. call
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
!注意:该方法的语法和作用与 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。
/**
* _call
*
* @param { context } context
* @param { arguments } arguments
*/
Function.prototype._call = function(context) {
// 如果没有传或传的值为空对象 context指向window
context = context || window
let fn = Symbol(context)
context[fn] = this //给context添加一个方法 指向this
// 处理参数 去除第一个参数this 其它传入fn函数
let args = [...arguments].slice(1) //[...xxx]把类数组变成数组,arguments为啥不是数组自行搜索 slice返回一个新数组
context[fn](...args) //执行fn
delete context[fn] //删除方法
}
var obj = {
name: 'Bob',
age: '18',
fn() {
console.log(`My name is ${this.name}, my age is ${this.age}`)
}
}
var dog = {
name: 'Snoopy',
age: 3
}
obj.fn.call(dog,'daddata','ttt','yuyuyuuy') // My name is Snoby, my age is 3
obj.fn._call(dog,'daddata','ttt','yuyuyuuy') // My name is Snoby, my age is 3
2. apply
类似的,apply方法实现一样,只是参数不一样
Function.prototype._apply = function(context) {
// 如果没有传或传的值为空对象 context指向window
context = context || window
let fn = Symbol(context)
context[fn] = this
let arg = [...arguments].slice(1)
context[fn](arg) //执行fn
delete context[fn] //删除方法
}
3. bind
bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
相较于call、apply, bind 区别还是很大的,分析一下bind的特点:1、改变this 2、返回一个绑定this的函数 3、接收多个参数 4、支持柯里化形式传参 fn(1)(2)
!注意: bind 方法与 call、apply 最大的不同就是前者返回一个绑定上下文的函数,而后两b者是直接执行了一个函数
/**
* _bind
*
* @param {*} context
*/
Function.prototype._bind = function (context) {
//返回一个绑定this的函数,我们需要在此保存this
let self = this
// 可以支持柯里化传参,保存参数
let arg = [...arguments].slice(1)
// 返回一个函数
return function () {
//同样因为支持柯里化形式传参我们需要再次获取存储参数
let newArg = [...arguments]
// 返回函数绑定this,传入两次保存的参数
//考虑返回函数有返回值做了return
return self.apply(context, arg.concat(newArg))
}
}