apply,call,bind详解

本文详细介绍了JavaScript中apply、call和bind的区别与使用,包括它们如何改变函数内部的this指向。通过源码实现,解释了它们的参数处理方式,并提供了一个面试题,涉及原型继承和bind的高级用法,展示了如何实现一个兼容bind功能的函数,以确保构造函数的继承和正确执行。

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

apply,call,bind详解

三者区别

  • apply,call,bind都能改变函数内部this指向
  • apply,call会运行函数且返回函数结果,区别只是参数传递方式不一样
  • bind不会运行函数,只绑定this且传参,依然返回一个函数

一、apply源码实现

实现之前,先写一下我们的测试案例

	var obj = {
		a: 1,
		b: 2
	}
	function add(c, d){
		return this.a + this.b + c + d;
	}
	console.log(add.myApply(obj)  ) //  期望能 返回3
	写之前请注意两点:
  1. apply需要运行调用函数
  2. 需绑定this指向
Function.prototype.myApply = function(context){
	if(typeof this !== 'function'){
		console.error('error: this is not a function');
	}
	// 保存this
	context.fn = this;
	// 处理参数,注意第二个参数是数组形式
	let [args] = [...arguments].slice(1);
	
	let result =  context.fn(...args);
	delete context.fn
	return result;
}

运行截图如下:
在这里插入图片描述

可以看到函数中的this.a和this.b都拿到obj中的值了,说明没问题.

二、call

call与apply大致相同,只是参数处理稍微有点区别,感兴趣的同学可以自己去试试

三、bind

要点:

  1. 更改this指向
  2. 返回的还是一个函数
  3. 参数处理
Function.prototype.myBind = function(context){
	if(typeof this !== 'function'){
		console.error('error: this is not a function');
	}
	 let self = this;
	 let args = [...arguments].slice(1);
	 let fn = function(){
		return self.apply(context, args.concat([...arguments]))
	}
	return fn;
}

测试案例不变,结果如下:

在这里插入图片描述

面试题进阶

题目: 实现如下代码中的bind,可以让success成功打印出来

function Animal(name, color) {
        this.name = name;
        this.color = color;
    }
    Animal.prototype.say = function () {
        return `I'm a ${this.color} ${this.name}`;
    }
    const Cat = Animal.bind(null, 'cat');
    const cat = new Cat('white');
    if (cat.say() === "I'm a white cat" && cat instanceof Cat && cat instanceof Animal) {
        console.log('success')
    }

这一题主要考的是继承,有几点要素:

  1. 原型继承
  2. apply只能继承对象的内部属性,不能继承其原型(prototype)
Function.prototype.bind = function (context) {
        let self = this;
        let args = Array.prototype.slice.call(arguments, 1);
        let bound = function () {
            let boundArgs = args.concat(Array.prototype.slice.call(arguments));
            self.apply(this, boundArgs);
        }
        bound.prototype = new self()
        return bound;
    }

运行成功,没有问题。
要注意这里的bind返回的应该还是一个构造函数,且能继承绑定函数的内部属性以及原型。

你学会了吗?

<think>好的,我现在需要详细解释JavaScript中的callapplybind方法,并提供使用示例。首先,我得回忆一下这三个方法的基本概念和区别。 callapply都是用来调用函数,并且改变函数内部的this指向。它们的区别在于参数传递方式不同:call接受参数列表,而apply接受数组。例如,func.call(obj, arg1, arg2)和func.apply(obj, [arg1, arg2])。 bind方法则是创建一个新的函数,永久绑定this值和部分参数,之后无论怎么调用这个新函数,this都不会改变。比如,var boundFunc = func.bind(obj); boundFunc()。 接下来,我需要结合示例来说明。比如,用callapply实现对象间方法的借用。例如,obj1有一个方法,obj2没有,可以通过call来调用obj1的方法,并让this指向obj2。 然后,要注意参数传递的不同。比如,Math.max.apply(null, array)可以展开数组作为参数,而call则需要逐个传入参数,这在参数数量不确定时apply更方便。 还要提到bind的应用场景,比如在事件处理函数中固定this,或者部分参数的应用。例如,setTimeout中使用bind确保回调函数中的this正确。 需要注意的细节是,bind后的函数无法再通过callapply改变this,这是硬绑定。例如,引用[3]中的例子说明即使多次bind,也以第一次为准。 需要确保示例代码正确,比如函数调用的语法,以及参数的正确传递。同时,要区分普通函数和箭头函数在this绑定上的差异,但这个问题用户可能没有提到,可以暂时不提。 最后,总结三者区别:调用时机、参数形式、返回值类型。call/apply立即执行,bind返回绑定后的函数。 现在要检查是否有遗漏点,比如性能差异或适用场景,比如apply处理数组参数在ES6中可以用扩展运算符替代,但了解apply仍有必要。 确保引用对应的注释正确,比如引用[1]提到call的语法,引用[2]解释this绑定,引用[3]说明bind的硬绑定特性。 可能还需要提供手写实现的示例,但用户没有明确要求,但引用[2]提到了手写实现,可以适当提及或作为扩展内容。 整理结构,分点讲解每个方法,每个方法后跟示例,最后总结对比表格,以及相关问题。确保代码格式正确,使用中文解释,数学公式用$...$,但这里可能用不上,但按系统指令需注意。</think>### JavaScriptcallapplybind方法详解及示例 #### 一、核心功能与语法 1. **`call`方法** - **功能**:立即调用函数,显式绑定`this`值并传递**参数列表** - **语法**: ```javascript function.call(thisArg, arg1, arg2, ...) ``` - **示例**: ```javascript const person = { name: 'Alice' }; function greet(age) { console.log(`${this.name} is ${age} years old`); } greet.call(person, 25); // 输出:Alice is 25 years old ``` 通过`call`将`greet`的`this`绑定到`person`对象[^1]。 2. **`apply`方法** - **功能**:与`call`类似,但参数以**数组形式传递** - **语法**: ```javascript function.apply(thisArg, [argsArray]) ``` - **示例**: ```javascript const numbers = [5, 2, 8]; const max = Math.max.apply(null, numbers); console.log(max); // 输出:8 ``` 此处`apply`展开数组作为参数,等价于`Math.max(5, 2, 8)`[^2]。 3. **`bind`方法** - **功能**:返回一个绑定了`this`和部分参数的**新函数**(延迟执行) - **语法**: ```javascript function.bind(thisArg, arg1, arg2, ...) ``` - **示例**: ```javascript const car = { brand: 'Tesla' }; function showModel(year) { console.log(`${this.brand} Model ${year}`); } const boundFunc = showModel.bind(car); boundFunc(2023); // 输出:Tesla Model 2023 ``` `bind`创建的新函数`boundFunc`永久绑定`this`为`car`[^3]。 #### 二、关键区别对比 | 方法 | 执行时机 | 参数形式 | 返回值类型 | 是否可覆盖`this` | |----------|----------|----------------|------------------|------------------| | `call` | 立即执行 | 参数列表 | 原函数返回值 | 是 | | `apply` | 立即执行 | 数组 | 原函数返回值 | 是 | | `bind` | 延迟执行 | 参数列表或部分 | 绑定后的新函数 | 否(硬绑定) | #### 三、进阶应用场景 1. **`call`实现继承** ```javascript function Animal(type) { this.type = type; } function Dog(type, name) { Animal.call(this, type); // 继承Animal属性 this.name = name; } const myDog = new Dog('哺乳动物', 'Buddy'); console.log(myDog.type); // 输出:哺乳动物 ``` 2. **`apply`合并数组** ```javascript const arr1 = [1, 2]; const arr2 = [3, 4]; arr1.push.apply(arr1, arr2); // 等价于arr1.push(3,4) console.log(arr1); // 输出:[1, 2, 3, 4] ``` 3. **`bind`解决事件回调的`this`丢失** ```javascript class Button { constructor() { this.text = 'Click me'; this.element = document.createElement('button'); this.element.addEventListener('click', this.handleClick.bind(this)); } handleClick() { console.log(this.text); // 正确输出:Click me } } ``` #### 四、注意事项 - **箭头函数**:三者对箭头函数无效,因其`this`由词法作用域决定 - **性能**:频繁调用`bind`可能产生内存开销(每次返回新函数) - **硬绑定特性**:`bind`后的函数再使用`call`/`apply`无法修改`this`[^3] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值