「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。
一、call
**语法**
function.call(thisArg, arg1, arg2, ...)
参数说明
thisArg:可选的。在 function 函数运行时使用的 this 值。
请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,
则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。
arg1, arg2, ... 参数列表。
返回值:使用调用者提供的 this 值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined。
手写实现
Function.prototype.myCall = function(context) {
// 这里的this是调用myCall的那个方法,context是我们想要this绑定到的对象
// 我们知道函this 永远指向最后调用它的那个对象
// 所以我们想了个办法把this赋值给context上的一个方法,此时方法去执行时,this就指向了context
// 在非严格模式下,context为 null 或 undefined 时替换为指向全局对象
var context = context || window
context.fn = this
// 拿到参数
var args = [...arguments].slice(1)
let result = context.fn(...args)
delete context.fn
return result
}
二、apply
**语法**
func.apply(thisArg , [ argsArray])
参数说明
thisArg: 必选的。在 func 函数运行时使用的this值。
请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,
则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。
argsArray: 可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 `func` 函数。
如果该参数的值为 null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。
返回值:调用有指定this值和参数的函数的结果。
手写实现
Function.prototype.myApply = function(context) {
var context = context || window
context.fn = this
let result
// apply和call 差不多一样的,只是参数变成了一个数组
result = arguments[1] ? context.fn(...arguments[1]) : context.fn()
delete context.fn
return result
}
三、bind
**语法**
function.bind(thisArg[, arg1[, arg2[, ...]]])
参数说明
thisArg: 调用绑定函数时作为 this 参数传递给目标函数的值。 如果使用new运算符构 造绑定函数,则忽略该值。
当使用 bind 在 setTimeout 中创建一个函数(作为回调提供)时,作为 thisArg 传递的任何原始值都将转换为 object。
如果 bind 函数的参数列表为空,或者thisArg是null或undefined,执行作用域的 this 将被视为新函数的 thisArg。
arg1, arg2, ... 当目标函数被调用时,被预置入绑定函数的参数列表中的参数。
返回值:返回一个原函数的拷贝,并拥有指定的 this 值和初始参数。
手写实现
我们实现了我们的第一版
Function.prototype.myBind = function(context) {
const fn = this
// 拿到参数
var args = [...arguments].slice(1)
// bind需要返回一个新的方法
const result = function () {
// 由于返回的函数里面也可能会有参数,我们拿到他
resultArgs = [...arguments]
// 我们使用apply的方法去实现
return fn.apply(context, args.concat(resultArgs));
}
return result
}
我们看一个原生bind的调用结果
const yJiang = {
name: "yJiang",
say: function (age, hobby) {
console.log(`我叫${this.name} ${age}岁 爱好${hobby}`)
}
}
const xiaoY = {
name: "xiaoY"
}
const aa = yJiang.say.bind(xiaoY, 24)
const bb = new aa('唱歌')
我们发现this.name为undefined。我们知道当返回的函数aa作为构造函数去调用的时候,this指向的是实例对象。
于是,我们知道在返回的新函数里面,我们需要加一个this的判断
Function.prototype.myBind = function(context) {
const fn = this
// 拿到参数
var args = [...arguments].slice(1)
// bind需要返回一个新的方法
const result = function () {
// 由于返回的函数里面也可能会有参数,我们拿到他
resultArgs = [...arguments]
// 我们使用apply的方法去实现
// 在这里我们需要做一个this的判断
return fn.apply((this instanceof result ? this : context), args.concat(resultArgs));
}
return result
}
call、apply、bind的区别
对于三者,我们知道
- 他们都可以改变this的指向
- 第一个参数都是要指向的对象
- 他们都可以添加参数。
区别的话
- call、apply主要区别在于参数,call是一个参数列表而aplly是一个参数数组
- bind和他们的区别在于,它返回的是一个新函数,然后再去执行调用函数,并且可以继续传递参数。