react闲谈——apply、call和spread运算符

前端之家收集整理的这篇文章主要介绍了react闲谈——apply、call和spread运算符前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

本章和react没有多大关系,纯粹是JavaScript语法探讨。

apply和call想必都不陌生了,那么spread是什么呢?它的中文名称叫做“扩展运算符”,是ES2015定义的语法。
这3者有着密切的关联,如果你掌握了apply和call,那么等你看完spread的用法,会发现新大陆。

apply
前端面试中,很多面试官会问你,apply是做什么的?apply和call的区别?

你可以告诉面试官,apply和call只有一个区别,就是传入的参数格式不同,apply传入一个数组参数 [argsArray],而call传入参数列表 arg1,arg2,...

如果你还不懂,那么请详细看。

1、apply的语法结构

有2个参数
thisArg:在 fun 函数运行时指定的 this 值,非严格模式下,也就是没有写"use strict",通常这个值设置为null或者undefined,则指向全局对象(大部分是时候是window)
argsArray:数组对象或者类数组对象,类数组对象只支持ES5,你可以不传任何参数,则为null 或 undefined。
fun.apply(thisArg,[argsArray])

2、apply的用法

有3种用法
a(使用apply链接构造器:和本文无关)
b(在monkey-patching中使用apply)

c(使用apply和内置函数):内置函数有很多,比如Array实现的内置函数、Math实现的内置函数,...

案例1:假设我们定义2个数组,使用apply调用Array的内置函数push(),可以写成下面这样。

var arr1 = [1,3,4]
var arr2 = [2,4,5]
//第一个参数表示正在调用调用push()的对象,这行代码的意思是说把arr2的参数传入arr1,你可以看成是arr1.push(arr2)这种行为,但不是等价的。
Array.prototype.push.apply(arr1,arr2)  //[1,2,5]
//类似下面这种写法,他们的输出是一样的。
arr2.forEach(function(value) {
arr1.push(value)
}) // [1,5]

案例2:假设我们调用内置函数Math的max()方法,使用apply可以写成下面这样。

var num = [6,10,8];
Math.max.apply(null,num); // null说明当前函数执行的上下文是在全局作用域,输出10

//如果换成for循环来判断最大值,恐怕你又得写多几行代码了。

总结:apply作为内置函数调用传参是最经常使用的场景,唯一的难点在于指定第一个参数的运行环境,毕竟一个this可以难倒一大批前端工程师。

call

call和apply类似,你掌握了apply,也就会用call了。

1、call的语法结构:

thisArg:标准叫法,指向当前调用函数的上下文。不扯这么难听的叫法,和apply的thisArg是完全一样的。
arg1,arg3,...:参数列表,对,这就是和apply唯一的区别,可以传入多个参数列表。
fun.call(thisArg,arg1,...)

2、call的用法

也有3种用法

a(使用call方法调用父构造函数):我就不重新构造一个父类函数了,还是拿刚才操作Array内置对象的方式来举例子。

案例1:假设我们定义2个数组,使用call调用Array的内置函数push(),可以写成下面这样。

var arr1 = []
var arr2 = [2,5]
var arr3 = ["大神","美女"]
//第一个参数表示正在调用调用push()的对象,这行代码的意思是说把arr2、arr3的参数传入arr1,注意call和apply的区别,call是把这个arr2和arr3数组参数传入,不会拆分数组元素。
Array.prototype.push.call(arr1,arr2,arr3)  
//你以为可能是[2,5,"大神","美女"]
//其实是这样的 输出[[2,5],["大神","美女"]]

案例2:假设我们调用内置函数Math的max()方法,使用call写成下面这样,但是他是错的,你知道为什么吗?

var num = [6,8];
Math.max.call(null,num); //输出NaN
//因为用call传max(num)的参数是一个数组,并不是数组元素列表,所以你还得靠for循环来实现。

b(使用call方法调用匿名函数):

案例:在一个for循环中,有一个匿名函数,设置一个定时器,想要在定时器定时输出循环的key和value。

var people = [
  {name: '阿里妈妈',age: 18},{name: '阿里爸爸',age: 22}
];
//一开始你可能会这样写:
for (var i = 0; i < people.length; i++) {
    (function (i) { 
        setTimeout(function () { 
          console.log(this.name + ': ' + this.age); 
        },i * 1000)
    })(i);
} //输出 
//"JS Bin Output : undefined"
//"JS Bin Output : undefined"

然后发现this指向不对,你可能会想到给函数设置一个变量指向当前的this,但是这样也不对,因为输出的this.name和this.age是指向数组animals的对象,那么这时候你需要给匿名函数用到call来绑定this指向的是animals里面循环的对象。

for (var i = 0; i < people.length; i++) {
    (function (i) { 
        setTimeout(function () { 
          console.log(this.name + ': ' + this.age); 
        },i * 1000)
    }).call(people[i],i);
} //输出
//"JS Bin Output : undefined"
//"JS Bin Output : undefined"

然而你会发现输出还是undefined,为什么呢?

原因在于匿名函数里面的this是指向了people[i]的对象,但是setTimeout里面的this是指向window的,所以你需要用到bind()绑定this。

for (var i = 0; i < people.length; i++) {
    (function (i) { 
//这里也可以用var  _this = this来改变this的上下文(指向)
        setTimeout(function () { 
          console.log(this.name + ': ' + this.age); 
        }.bind(this),i);
} //输出
//"阿里妈妈: 18"
//"阿里爸爸: 22"

好了,大功告成,你看懂没?

c(使用call方法调用函数并且指定上下文的'this'):
案例:定义一个people函数,用来输出name和age参数,接着定义一个参数对象,我们要把这个对象传入函数,使函数的this可以指向i对象,这样才能保证读取到i对象里面的key。

function people() {
  var arr = this.name + this.age;
  console.log(arr);
}
var i = {
  name: '阿里爸爸',age: 22
};
//如果你直接people(i),是读取不到的,因为people相当于构造函数,那么通过call的方式就简单了,直接下面这种形式。把people的this用call绑定到i对象上,你用apply也是一样的。
people.call(i);  ===  people.apply(i)
//输出 "阿里爸爸22"

总结:call和apply用法是类似的,唯一的区别在于参数传入的方式,apply是传入一个数组或者类数组参数,call可以传入多个。

spread
主角隆重登场!!!
我们叫他扩展运算符,他的写法是...(三个小点点)
请在 http://babeljs.cn/ 测试下面代码
spread出现在ES2015标准,如果你是老前端,只是听过这个语法,但是没有用过,那么,非常欢迎你使用它。

还记得我讲apply的时候用到的操作内置函数的案例吗?

我们可以用spread来实现。

编译前:

var arr1 = [1,5]
arr1.push(...arr2)
console.log(arr1) // [1,5]

var num = [6,8];
var max = Math.max(...num)
console.log(max) // 10

编译后:

var arr1 = [1,4];
var arr2 = [2,5];
arr1.push.apply(arr1,arr2);
console.log(arr1); // [1,8];
var max = Math.max.apply(Math,num);
console.log(max); // 10

还记得我讲call 的时候用到的操作内置函数的案例吗?

编译前:

var arr1 = []
var arr2 = [2,"美女"]

arr1.push(...arr2,...arr3)
console.log(arr1) // [2,"美女"]

编译后:

var arr1 = [];
var arr2 = [2,5];
var arr3 = ["大神","美女"];

arr1.push.apply(arr1,arr2.concat(arr3));
console.log(arr1); // [2,"美女"]

看到这里,你发现spread的用法了吗?

它可以把我们的数组元素解构出来,还可以解构类数组,这里就不讲解了。

**总结:1、在一些内置函数调用传参的时候,我们可以不再用apply和call,用spread运算符即可。2、apply和call用途还是非常广的,当然还有bind,最近几年,你可能都离不开它们。3、在react开发中,spread运算符在各个组件中运用非常广泛,你可以更加详细的了解它。**

原文链接:https://www.f2er.com/react/304622.html

猜你在找的React相关文章