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

让我们来详细讲解一下"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日

相关文章

  • JavaScript实现弹出模态窗体并接受传值的方法

    下面是 JavaScript 实现弹出模态窗体并接受传值的方法的攻略: 原理分析 在 JavaScript 中,我们可以通过调用 window.open 方法来打开一个新窗口,也可以通过调用 window.showModalDialog 方法来打开模态窗口。其中,模态窗口是一种类似于对话框的窗口方式,可以禁止用户在不关闭窗口的情况下操作父窗口。 在模态窗口中…

    JavaScript 2023年6月11日
    00
  • php实现数组中索引关联数据转换成json对象的方法

    当我们需要将 PHP 中的索引关联数组转换为 JSON 对象时,可以使用 json_encode() 函数完成这个任务。 下面是一个将 PHP 关联数组转换为 JSON 对象的示例代码: <?php $data = array( ‘name’ => ‘John’, ‘age’ => 30, ’email’ => ‘john@examp…

    JavaScript 2023年6月11日
    00
  • JavaScript使用Math.random()生成简单的验证码

    生成验证码是网站开发中常见的需求之一,通过JavaScript的Math.random()方法可以生成随机数,进而生成简单的验证码。下面是一个完整的攻略,会详细讲解生成验证码的步骤以及两条示例说明。 生成验证码的步骤 1. 定义生成验证码的函数 在JavaScript中,可以通过函数来生成验证码。我们可以定义一个名为generateCode的函数,该函数可返…

    JavaScript 2023年5月28日
    00
  • defer属性导致引用JQuery的页面报“浏览器无法打开网站xxx,操作被中止”错误的解决方法

    当我们在HTML页面中引入JQuery时,可以给<script>标签添加一个defer属性,来告诉浏览器在文档解析完成后再加载并执行该JS文件。但是,如果在使用defer属性时,JS文件中存在依赖JQuery的代码,就会导致页面在加载时出现错误。 这里提供两种解决方法: 方法一:将defer移除或替换为async 解决问题的一种方法是将<s…

    JavaScript 2023年6月10日
    00
  • 为什么要使用 Rust 语言、Rust 语言有什么优势

    为什么要使用 Rust 语言、Rust 语言有什么优势 1. 什么是 Rust 语言? Rust 是一种多范式系统编程语言,旨在提供可靠的内存安全和高性能 abstractions 的开发体验。特别是,它解决了传统 C 和 C++ 语言中的一些缺陷,如空指针、缓冲区溢出等,同时通过所有权机制解决了内存安全问题。Rust 是 Mozilla Foundatio…

    JavaScript 2023年5月28日
    00
  • 利用jquery的获取JS文件中的字符串内容

    获取 JS 文件中的字符串内容,可以使用 jQuery 的 AJAX 功能来实现。具体步骤如下: 使用 $.get() 或 $.ajax() 函数向指定的 JS 文件发送 HTTP 请求,获取文件内容。 示例1: $.get(‘script.js’, function(data) { console.log(data); }); 在这个示例中,我们使用 $.…

    JavaScript 2023年5月27日
    00
  • JS 中使用Promise 实现红绿灯实例代码(demo)

    下面是使用 Promise 实现红绿灯实例代码的攻略。 红绿灯实例代码 在使用 Promise 实现红绿灯实例代码之前,我们需要了解什么是红绿灯实例代码。红绿灯实例代码是一种模拟红绿灯闪烁的代码,通常用于展示 Promise 的作用。 以下是基于 Promise 实现红绿灯实例代码的完整攻略: 1. 创建 Promise 对象 在开始使用 Promise 实…

    JavaScript 2023年6月10日
    00
  • js function定义函数的几种不错方法

    当我们在编写JavaScript程序时,经常需要定义函数,下面介绍JavaScript定义函数的几种不错方法。 方法一:函数声明 函数声明是最常用的一种定义函数的方法,只需要使用function关键字即可。 function funcName(parameter1, parameter2, …parameterN) { // 函数体 } 其中,funcN…

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