react闲谈——apply、call和spread运算符
本章和react没有多大关系,纯粹是JavaScript语法探讨。 apply和call想必都不陌生了,那么spread是什么呢?它的中文名称叫做“扩展运算符”,是ES2015定义的语法。 apply 你可以告诉面试官,apply和call只有一个区别,就是传入的参数格式不同,apply传入一个数组参数 [argsArray],而call传入参数列表 arg1,arg2,... 如果你还不懂,那么请详细看。 1、apply的语法结构 有2个参数 2、apply的用法 有3种用法 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是完全一样的。 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'): 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 还记得我讲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运算符在各个组件中运用非常广泛,你可以更加详细的了解它。** (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |