1. call
的实现
call()
方法调用一个函数,其具有一个指定的this
值和分别地提供的参数(参数的列表)。
call
的性能要高于apply
。
call
()方法作用和apply()
方法类似,只有一个区别,就是call()
方法接受的是若干个参数的列表,而apply()
方法接受的是一个包含多个参数的数组。
语法:
function.call(thisArg, arg1, arg2, ...)
// 思路:判断this是否传递,参数是否存在,删除创建的函数
// 原理:把当前的函数在指定的上下文环境中(对象)运行
// 当传入null 或 undefined 时 自动替换为全局对象
Function.prototype._call = function (context) {
// 忽略了一些特殊情况 只有null 和 undefined时替换为window
// var context = context || window
var context = context == null ? window : (typeof context === 'object' ? context : Object(context))
// 获取参数
// var args = Array.prototype.slice.call(arguments)
var args = [...arguments].slice(1)
// var result = eval('context.fn('+args+')')
var result = context.fn(...args)
delete context.fn
return result
}
// 测试
var obj = {
name: "future",
date: "2021"
}
function sum(a, b) {
console.log(this.name, a, b)
}
sum._call(obj, 20, 30) // ⇒ future 20 30
2. apply
的实现
apply()
方法调用一个函数,其具有一个指定的this
值,以及作为一个数组(或类似数组的对象)提供的参数。
使用语法:
func.apply(thisArg, [argsArray])
// call/apply的区别只有参数:call是接收多个单个的参数,apply是接收一个数组
// 因为第二个参数是数组,所以要处理是否存在
Function.prototype._apply = function (context) {
var context = context == null ? window : (typeof context === 'object' ? context : Object(context))
context.fn = this
var result
// 判断是否存在第二个参数
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
delete context.fn
return result
}
// 测试
var obj = {
name: "future",
date: "2021"
}
function sum(a, b) {
console.log(this.name, a, b)
}
sum._apply(obj, [100, 200, 300, 400]) // ⇒ future 100 200
3. bind
的实现
bind()
方法创建一个新的函数,当被调用时,将其this
关键字设置为提供的值(bind
的第一个参数),在调用新函数时,在任何提供之前提供一个给的参数序列。它不会被立即执行,只有在被调用时执行。
语法:
func.bind(thisArg[, arg1[, arg2[, ...]]])
// 思路:接收保存this指向,接收保存参数,返回一个新创建的函数
// 原理:同call、apply在指定的上下文环境(对象)中创建一个函数,使用时this时钟指向这里
Function.prototype._bind = function (context) {
// 不是函数调用时 报错
if (typeof this !== "function") {
throw new Error("not is function")
}
var self = this
// 保存参数 [...arguments].slice(1)
var args = Array.prototype.slice.call(arguments, 1)
var newf = function () { };
var fBound = function () {
// 保存调用时的参数
var args2 = Array.prototype.slice.call(arguments)
var argSum = args.concat(args2)
// if (this instanceof newf) return self.apply(this, argSum)
// return self.apply(context, argSum)
// 合并简写
return self.apply(this instanceof newf ? this : context, argSum)
}
// 因为当返回的函数被当做构造函数时绑定的this会失效,会指向new出的实例化对象
// 所以在此处通过修改返回函数的原型来解决,上边声明一个空函数newf进行中转
newf.prototype = this.prototype
fBound.prototype = new newf()
return fBound
}
// 测试
var obj = {
name: "future",
date: "2021"
}
function getName() {
console.log(this.name, this.date)
}
var f = getName._bind(obj)
f() // ⇒ future 2021