javascript函数的call、apply和bind的原理及作用详解

yizhihongxing

让我们来详细讲解一下"JavaScript函数的call、apply和bind的原理及作用详解"。

一、基本概念

在JavaScript中,函数也是一种对象,因此我们可以像其他对象一样,给函数绑定属性或方法,并可以改变函数在执行时的作用域和this的指向。其中,call、apply和bind就是改变函数执行时上下文的方法。

1. call方法

call是一个函数的方法,在函数执行时,它可以将参数作为单个参数传入。函数调用时,第一个参数将成为this,后面的参数将作为传入函数的参数。call函数可以改变函数的上下文(即this指向)。

func.call(thisArg[, arg1[, arg2[, ...]]])

其中,thisArg是在调用函数时所设置的this值,arg1、arg2等参数是传递给函数的参数。

下面看一个示例:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

function sayHello() {
  console.log(`Hello, My name is ${this.name}, I'm ${this.age} years old.`);
}

const person1 = new Person('John', 18);
sayHello.call(person1); // 输出: Hello, My name is John, I'm 18 years old.

在上面的例子中,我们定义了一个Person构造函数和一个sayHello函数。使用call方法将sayHello函数的上下文设置为person1,并且将sayHello函数作为person1的方法来调用,这样就实现了Person构造函数和sayHello函数之间的关联,输出结果符合我们的预期。

2. apply方法

apply与call方法有所不同,它是一个函数的方法,在函数执行时,也可以将参数作为单个参数传入。但是,它是将参数作为数组传入。函数调用时,第一个参数将成为this,第二个参数将作为传入函数的参数组成的数组。apply函数同样可以改变函数的上下文(即this指向)。

func.apply(thisArg, [argsArray])

其中,thisArg是在调用函数时所设置的this值,argsArray是一个数组,包含要传入的参数。

下面看一个示例:

const fruits = ['apple', 'orange', 'banana'];
console.log(Math.max.apply(null, fruits)); //输出: NaN

在上面的例子中,我们使用apply方法将fruits数组作为参数列表传入了Math.max中,而不是将它们作为单独的参数传入。由于Math.max只接收数字类型的参数,所以返回值为NaN。

3. bind方法

bind方法与call和apply的功能类似,也用于改变函数的上下文,但是它不会立即调用函数,而是返回一个新的函数,这个新函数会把调用bind函数时传入的参数拼接在调用新函数的参数列表之前。

func.bind(thisArg[, arg1[, arg2[, ...]]])

其中,thisArg是在调用函数时所设置的this值,arg1、arg2等参数是传递给函数的参数。

下面看一个示例:

const Person = {
  name: 'John',
  sayHello: function () {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const Person2 = {
  name: 'Lily'
}

const sayHello2 = Person.sayHello.bind(Person2);
sayHello2(); // 输出: Hello, my name is Lily

在上面的例子中,我们首先定义了一个Person对象,它有一个sayHello方法,并且该方法的上下文(即this)指向Person对象。由于我们想让sayHello的上下文指向Person2对象,我们使用了bind方法,将Person2对象作为bind的第一个参数,生成了一个新的sayHello2函数。再次调用sayHello2函数时,就会输出“Hello, my name is Lily”。

二、示例演示

下面提供两个关于这三种方法使用的实例,以帮助更好理解这三种方法的作用。

1. 用call方法实现继承

通过call可以实现继承,假设现在有一个Animal对象,我们需要从Animal对象派生出一个Cat对象,Cat对象有自己的属性和方法,但是也需要继承Animal的属性和方法,我们可以使用call来实现。

function Animal(name) {
  this.name = name;
}

Animal.prototype.sayHello = function() {
  console.log(`Hello, I'm ${this.name}`);
}

function Cat(name) {
  // 继承父类属性
  Animal.call(this, name); 
}

const cat1 = new Cat('Tom');
cat1.sayHello(); // 输出:Hello, I'm Tom

在上面的例子中,我们定义了Animal构造函数,它有一个name属性和一个sayHello方法。然后我们定义了一个Cat构造函数,它继承了Animal的属性和方法,并且在Cat的构造函数中调用Animal的构造函数中让子类继承父类的属性。

2. 用bind方法实现参数复用与柯里化

bind方法可以实现参数复用,将一个函数的一些参数固定下来,返回一个新的函数。较复杂的场景还能实现柯里化。

function add(a, b, c) {
  return a + b + c;
}

const addOne = add.bind(null, 1);
const sum = addOne(2,3); // 输出: 6

在上面的例子中,我们定义了一个add函数,接受三个参数,并返回三个参数的和。然后我们使用bind方法将add函数中的第一个参数a绑定为1,生成了一个新函数addOne。再次调用addOne时,只需要传入剩余的两个参数即可。

这样子的场景还不够复杂。请看:

function add(a, b, c, d) {
  return a + b + c + d;
}

//柯里化
const currying = (fn, ...args) => 
  fn.length > args.length ? 
    (...arguments) => currying(fn, ...args, ...arguments) : 
    fn(...args);

const addCurry = currying(add);
const addTwo = addCurry(2)(3);
const sum = addTwo(4)(5); // 输出:14

在上面的例子中,我们使用了函数柯里化,用bind方法对参数进行复用。currying函数的作用是接收一个函数fn和一些参数args,生成一个新函数。当新函数的参数个数达到了fn的参数个数时,就会调用fn函数,并且将之前的参数和新的参数一起传入。最终的结果就是我们依次调用addTwo(4)和addTwo(5),返回值为14。

三、总结

以上是关于call、apply和bind这三种方法的使用,同时为了更好理解它们,一并提供了两个示例。这三种方法对于函数的执行上下文(this指向)的改变是非常有用的,可以解决很多函数执行上下文的问题,对于函数的开发具有重要的价值。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:javascript函数的call、apply和bind的原理及作用详解 - Python技术站

(0)
上一篇 2023年6月10日
下一篇 2023年6月10日

相关文章

  • JS闭包与延迟求值用法示例

    JS闭包和延迟求值是JS中比较重要的概念,也是面试中常被问到的问题。下面我将给出JS闭包与延迟求值的完整攻略,并针对两个具体的示例进行说明。 一、JS闭包 1.1 什么是闭包 在JS中,闭包就是能够读取其他函数内部变量的函数。简单来说,闭包就是“内部函数记住并访问其外部作用域的能力”。 1.2 闭包的形成与作用 闭包的形成有两个条件:内部函数必须在外部函数内…

    JavaScript 2023年6月10日
    00
  • JS实现可以用键盘方向键控制的动画

    下面是JS实现可以用键盘方向键控制的动画的完整攻略。 1. 监听键盘事件 为了实现键盘控制,我们需要在页面中监听键盘事件。我们可以通过 window.addEventListener() 方法来添加监听器,如下所示: window.addEventListener(‘keydown’, function(event) { // 处理键盘事件 }); 该代码将…

    JavaScript 2023年6月11日
    00
  • Javascript 倒计时源代码.(时.分.秒) 详细注释版

    我来为你详细讲解“JavaScript 倒计时源代码(时.分.秒)详细注释版”的完整攻略。该源代码可以实现一个简单的倒计时功能,以时分秒的形式展示倒计时剩余时间。 首先,我们需要在 HTML 页面中创建对应的元素来显示倒计时。例如,我们可以使用以下代码: <div id="countdown"></div> 接着,…

    JavaScript 2023年5月27日
    00
  • JS创建对象的写法示例

    以下是关于JS创建对象的写法示例的完整攻略: 什么是JS对象 JS中的对象指的是一组键值对的集合。它们通过点号或中括号访问。 1.对象字面量创建对象 // 通过字面量的方式创建一个对象 const obj = { name: "Lena", age: 25, gender: "female", sayHi: funct…

    JavaScript 2023年5月27日
    00
  • javascript的replace方法结合正则使用实例总结

    JavaScript的replace方法是对字符串的操作方法,可以替换掉指定的字符串或正则表达式匹配到的部分。通常情况下,replace方法结合正则表达式的使用可以非常灵活和方便地操作字符串。下面我们来看一下replace方法结合正则表达式使用的实例总结。 正则表达式语法 在学习replace方法结合正则表达式的使用之前,我们需要了解一些常用的正则表达式语法…

    JavaScript 2023年5月28日
    00
  • javascript 闭包详解及简单实例应用

    JavaScript 闭包详解及简单实例应用 在 JavaScript 中,闭包是一个重要的概念,也是一个令人困惑的概念。理解闭包的概念和用法,可以大幅提高你的 JavaScript 编程水平。在这篇文章中,我们将介绍什么是闭包,为什么需要它们,并且演示几个具体的使用场景。 什么是闭包? 闭包是指在函数内部定义的函数,该函数可以访问在外部函数作用域中声明的变…

    JavaScript 2023年6月11日
    00
  • 详解JavaScript基于面向对象之创建对象(2)

    首先,你需要了解JavaScript中面向对象编程的概念。在JavaScript中,我们可以通过构造函数和原型链来实现面向对象编程。 第二篇文章“详解JavaScript基于面向对象之创建对象(2)”主要介绍了通过原型链来创建对象的方式。具体内容包括: 原型链是什么? 原型链是一种由多个对象组成的链式结构,这些对象通过原型链相互关联,在其中可以共享属性和方法…

    JavaScript 2023年5月27日
    00
  • JavaScript 图片预览效果 推荐

    JavaScript 图片预览效果是一种常见的 Web 前端功能,它可以让用户在网页中浏览图片时更加方便、便捷。本攻略将详细讲解如何使用 JavaScript 实现图片预览效果。下面是详细的步骤。 准备工作 在开始之前,我们需要准备以下内容: 一个 HTML 文件,其中包含需要预览的图片元素。 一个 JavaScript 文件,用于实现图片预览效果。 实现过…

    JavaScript 2023年6月10日
    00
合作推广
合作推广
分享本页
返回顶部