如何使用JavaScript中的调用、应用和绑定函数--附代码示例

103 阅读8分钟

在这篇文章中,我将用简单的例子解释如何在JavaScript中使用调用、应用和绑定。

我们还将实现一个例子,展示你如何用apply函数创建你自己的地图函数。

不多说了,让我们开始吧:

目录

前提条件

以下是你应该了解的一些情况,以便从本文中获得最大的收获:

定义

让我们再仔细看看我们在这里要学习的函数,了解它们的作用。

调用是一个帮助你改变调用函数的上下文的函数。通俗地说,它可以帮助你用任何你想要的值来替换函数中this 的值。

应用call 函数非常相似。唯一不同的是,在apply ,你可以传递一个数组作为参数列表。

绑定是一个帮助你创建另一个函数的函数,你可以在以后用提供的this 的新上下文执行这个函数。

现在我们将看看调用、应用和绑定函数的一些基本例子。然后我们将看一个例子,我们将构造我们自己的函数,类似于map函数。

如何在JavaScript中使用调用函数

call 是一个函数,你用它来改变函数内部 的值,并且用提供的参数来执行它。this

下面是call 函数的语法:


func.call(thisObj, args1, args2, ...)

其中:

  • func是一个需要用不同的this 对象来调用的函数
  • thisObj是一个对象或一个值,需要用函数中的this 关键字来替换。func
  • args1, args2是参数,用改变后的this 对象传递给调用的函数。

注意,如果你调用一个没有任何thisObj 参数的函数,那么JavaScript认为这个属性是一个全局对象。

现在我们有了一些关于什么是call 函数的上下文,让我们首先通过一些例子来更详细地了解它。

如何在JS中用不同的上下文调用一个函数

考虑一下下面的例子。它由3个类组成 -Car,Brand1, 和Brand2

function Car(type, fuelType){
	this.type = type;
	this.fuelType = fuelType;
}

function setBrand(brand){
	Car.call(this, "convertible", "petrol");
	this.brand = brand;
	console.log(`Car details = `, this);
}

function definePrice(price){
	Car.call(this, "convertible", "diesel");
	this.price = price;
	console.log(`Car details = `, this);
}

const newBrand = new setBrand('Brand1');
const newCarPrice = new definePrice(100000);

如果你仔细观察,你可以看到我们在两个场合使用call 函数来调用Car 函数。首先是在setBrand ,然后是在definePrice 函数中。

在这两个函数中,我们用代表各自函数本身的this 对象来调用Car 函数。例如,在setBrand ,我们用属于其上下文的this 对象调用Car 函数。definePrice 的情况也是如此。

如何在JS中调用一个没有参数的函数

请看下面的例子:

const newEntity = (obj) => console.log(obj);

function mountEntity(){
	this.entity = newEntity;
	console.log(`Entity ${this.entity} is mounted on ${this}`);
}

mountEntity.call();

在这个例子中,我们调用了没有thisObj 参数的函数mountEntity 。在这种情况下,JavaScript指的是全局对象。

如何在JavaScript中使用Apply函数

Apply 函数与Call 函数非常相似。callapply 之间的唯一区别是参数传递方式的不同。

apply ,参数可以以数组字面形式或新的数组对象形式传递。

下面是apply 函数的语法:

func.apply(thisObj, argumentsArray);

其中:

  • func是一个需要用不同的this 对象来调用的函数
  • thisObj是一个对象或一个值,需要用函数中的this 关键字来替换。func
  • argumentsArray可以是一个参数数组,数组对象,或者arguments关键字本身。

正如你在上面看到的,apply 函数有不同类型的语法。

第一种语法是简单的语法。你可以像下面这样传入一个参数数组:

func.apply(thisObj, [args1, args2, ...]);

第二种语法是,我们可以向它传递新的数组对象:

func.apply(thisObj, new Array(args1, args2));

第三种语法是我们可以传入arguments关键字的地方:

func.apply(thisObj, arguments); 

arguments是一个在函数中可用的特殊对象。它包含传递给函数的参数值。你可以在apply 函数中使用这个关键字来接受任何数量的任意参数。

关于apply ,最好的部分是我们不需要照顾传递给调用函数的参数数量。由于它的动态和多功能性,你可以在复杂的情况下使用它。

让我们看看与上面相同的例子,但这一次我们将使用apply 函数:

function Car(type, fuelType){
	this.type = type;
	this.fuelType = fuelType;
}

function setBrand(brand){
	Car.apply(this, ["convertible", "petrol"]); //Syntax with array literal
	this.brand = brand;
	console.log(`Car details = `, this);
}

function definePrice(price){
	Car.apply(this, new Array("convertible", "diesel")); //Syntax with array object construction
	this.price = price;
	console.log(`Car details = `, this);
}

const newBrand = new setBrand('Brand1');
const newCarPrice = new definePrice(100000);

而这里有一个例子,展示了你如何使用arguments 这个关键词:

function addUp(){
		//Using arguments to capture the arbitrary number of inputs
    const args = Array.from(arguments); 
    this.x = args.reduce((prev, curr) => prev + curr, 0);
    console.log("this.x = ", this.x);
}

function driverFunc(){
    const obj = {
        inps: [1,2,3,4,5,6]
    }
    addUp.apply(obj, obj.inps);
}

driverFunc();

如何在JavaScript中使用Bind函数

bind 函数创建了一个函数的副本,并将新的值传递给存在于调用函数内部的this

下面是bind 函数的语法:

func.bind(thisObj, arg1, arg2, ..., argN);

其中:

  • func是一个需要用不同的this 对象来调用的函数
  • thisObj是一个对象或一个值,需要用函数中的this 关键字来替换。func
  • arg1, arg2...argN- 你可以向调用的函数传递1个参数,也可以传递更多的参数,类似于call 函数。

然后,bind 函数返回一个新的函数,该函数由一个新的上下文组成,该上下文存在于调用函数内的this 变量。

func(arg1, arg2);

现在这个函数func ,以后可以用参数执行。

让我们看看一个经典的例子,如何在基于类的React组件的帮助下使用bind 函数:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 1
    };
  }
  handleCode() {
    console.log("HANDLE CODE THIS = ", this.state);
  }
  render() {
    return <button onClick={this.handleCode}>Click Me</button>;
  }
}

考虑一下上面的App组件,它构成了以下内容:

  • constructor 是一个被称为类的函数,并通过 关键字进行实例化。new
  • render 是一个执行/渲染JSX代码的函数。
  • handleCode 是一个类方法,记录组件的状态。

如果我们点击Click Me 按钮,那么我们将收到一个错误,说明:Cannot read properties of undefined (reading 'state')

你有没有想过为什么会出现这个问题?🤔🤔

你可能期望我们应该能够访问类的状态,因为handleCode 是一个类方法。但这里有一个问题。

  • this handleCode 里面的状态与类的 里面的状态不一样。this
  • 在一个类里面,this 是一个普通的对象,它的属性为非静态的类方法。但是在this 里面的handleCode 将指的是一个不同的上下文。
  • 说实话,在这种情况下,this 的价值取决于从哪里调用这些函数。如果你看到,handleCode 是在onClick 事件中被调用的。
  • 但在这个阶段,我们将得到undefined ,因为this 的上下文存在于handleCode 函数中。
  • 我们正试图调用一个未定义值的state 属性。因此,这导致了上述错误。

我们可以通过在handleCode 方法中提供正确的this 上下文来解决这个问题。你可以通过bind 方法来做到这一点:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 1
    };
   this.handleCode = this.handleCode.bind(this); //bind this function
  }
  handleCode() {
    console.log("HANDLE CODE THIS = ", this.state);
  }
  render() {
    return <button onClick={this.handleCode}>Click Me</button>;
  }
}

bind 将创建一个新的函数,并将其存储在this 对象内,并有一个新的属性作为handleCodeBind 将确保类的this 上下文被应用到handleCode 函数内的this

如何创建你自己的map 函数

现在我们有了所有必要的东西,让我们开始创建我们的own 地图函数。首先让我们了解一下建立我们的own 地图函数所需要的东西。

下面是map 函数的语法:

arr.map(func)

其中:

  • arr是一个数组,在这个数组上调用map。
  • func是需要在数组的每个元素上运行的函数。

map 函数的基本功能很简单。

它是一个遍历数组中每个元素的函数,并应用作为参数传递的函数。map的返回类型也是一个数组,func ,并应用于每个元素。

现在我们理解了这些要求,所以我们可以继续创建我们自己的map 函数。下面是我们的新函数map 的代码:

function newMap(func){
  let destArr = [];
  const srcArrLen = this.length;
  for(let i = 0; i < srcArrLen; i++){
    destArr.push(func.call(this, this[i]));
  }

  return destArr;
} 

让我们一点一点地理解上述函数:

  • 这个函数接受了一个名为func 的参数。它只不过是一个需要在数组的每个元素上调用的函数。
  • 代码的其他部分是很好解释的。我们将重点关注下面这一行。destArr.push(func.call(this, this[i]));
  • 这一行做了两件事:
    1.将变化推送到destArr
    2.在call 方法的帮助下执行func 。在这里,call 方法(如前几节所解释的)将执行func 方法,给存在于func 方法中的this 对象一个新值。

现在让我们来看看我们将如何执行我们的newMap 函数。下面这种为现有的原始数据类型添加新方法的方法是不推荐的,但为了本文的目的,我们还是要这样做。

注意:不要在你的生产代码中遵循下面的方法。这可能会对现有的代码造成损害。

Object.defineProperty(Array.prototype, 'newMap', {
  value: newMap
}); 

defineProperty 我们在 里面创建一个新的属性。Array.prototype

一旦这样做了,我们就可以在数组上执行我们新的map函数了:

const arr = [1,2,3];
const newArr = arr.newMap(item => item + 1);
console.log(newArr);

总结

这篇文章通过例子向你展示了调用、应用和绑定函数的作用。

因此,我们来简单地谈谈这些函数:

  • 调用、应用和绑定是帮助你改变调用函数中的this 关键字的上下文的函数。
  • 我们看到每个函数可以用不同的方式调用--例如,用apply ,你可以执行一个带有参数数组的函数,而用call ,你可以执行同样的函数,但参数通过逗号分散。
  • 这些函数在React的基于类的组件中真的很有用。

谢谢你的阅读!