小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前言
今天这篇手写系列也是我自己在复习过程中的一则笔记,能够帮助我更好地理解并掌握call、apply和bind函数的底层逻辑。废话不多说,我们开始。
手写call
根据 MDN关于call的定义,call() 方法使用一个指定的this值和单独给出的一个或多个参数来调用一个函数。举一个简单的栗子。
// Function.prototype.call()样例
function fun(arg1, arg2) {
console.log(this.name)
console.log(arg1 + arg2)
}
const obj = { name: '小陈同学吗' }
// 接受的是一个参数列表;方法立即执行
fun.call(obj, 1, 2)
// 输出:小陈同学吗 3
下面来实现自己的mycall,需要考虑的地方是,如果第一个参数为null或者undefined的,那么对象就会转变为window。
Function.prototype.myCall = function(context) {
if (typeof context === "undefined" || context === null) {
context = window
}
//context=context||window 和上面的代码一样
context.fn = this//(因为call的调用方式形如:myFun.call(obj),因此此时call方法的this指向为myFun,因此context.fn = this即为context.fn = myFun)
const args = [...arguments].slice(1)//第一个参数为context,要去除
const result = context.fn(...args)
delete context.fn
return result
}
手写apply
注意: 该方法的语法和作用与 call()方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。
// Function.prototype.apply()样例
function fun(arg1, arg2) {
console.log(this.name)
console.log(arg1 + arg2)
}
const obj = { name: '小陈同学吗' }
// 接受的是一个参数列表;方法立即执行
fun.apply(obj, [1,2])
// 输出:小陈同学吗 3
这个地方我是这样记忆的:Apply开头字母是A,和Array开头一样,因此apply传递数组。
Function.prototype.myApply = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Error.....')
}
context = context || window
context.fn = this
let result
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
delete context.fn
return result
}
手写bind
call()和apply()改过this的指向后,会再执行函数,bind()改过this后,不执行函数,会返回一个绑定新this的函数。
bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被指定为bind()的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
Function.prototype.myBind = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Error....')
}
//返回一个绑定this的函数,这里我们需要保存this
const _this = this
const args = [...arguments].slice(1)
//返回一个函数
return function F() {
//因为返回一个函数,我们可以new F()需要判断能当做构造函数吗
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}
结语
以上就是本次手写JS的内容,实现了自己的简单版call、apply和bind函数,但还是有瑕疵的地方,需要再深入学习研究。