JavaScript之call、apply、bind的模拟实现

这篇博客详细介绍了JavaScript中函数方法call、apply和bind的实现原理及用法。通过示例展示了如何在不同上下文中调用函数,并解释了它们之间的区别。call方法接受单个参数列表,apply方法接收参数数组。bind方法则用于创建一个新的函数,确保调用时this关键字指向预定的对象,并可以预设参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值