这个怎么运作:

Array#reduceRight is the trickiest of the JS APIs to understand. Even battle-hardened developers with 20+ years of experience often find themselves scurrying back to MDN docs or Google when they faced with reduceRight. I am not left out :) In fact, I am the worst, I forget how reduceRight works 3 seconds after reading about it in MDN(my fav JS docs site).

一个 rray#reduceRight是最棘手的JS API来理解。 即使是具有20多年经验的,经过艰苦奋斗的开发人员,在遇到reduceRight时,也常常会急于回到MDN文档或Google。 我并没有被排除在外:)实际上,我是最糟糕的,我忘记了在MDN(我最喜欢的JS文档站点)上读到reduceRight后三秒钟如何工作。

So here, we will look deep at its mechanics.

因此,在这里,我们将深入研究其机制。

POSTly is a web-based API tool that allows for fast testing of your APIs (REST, GraphQL). Check it out here:

POSTly是基于Web的API工具,可用于快速测试API(REST,GraphQL)。 在这里查看:

结构体 (Structure)

(method)Array<any>.reduceRight(callbackFn:(previousValue: any, currentValue: any,currentIndex: any, array: any[]) => any,initialValue?: any): any

Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result and is provided as an argument in the next call to the callback function.

以降序调用数组中所有元素的指定回调函数。 回调函数的返回值是累加结果,并在下一次对回调函数的调用中作为参数提供。

In simple terms, this method reduces all elements in an array to a single value starting from the rightmost element.

简而言之,此方法将数组中的所有元素从最右边的元素开始减少为单个值。

What to do we mean by right-most element?

最右边的元素是什么意思?

const arr = [2, 3, 4, 5, 6, 7, 8, 9]

reduceRight will start from 9 downwards, hitting 8, 7, 6, till to 2. Yeah, 9 is the right-most element in the arr array, right? :):

reduceRight将从9向下开始,达到8、7、6,直到2。是的,9是arr数组中最右边的元素,对吗? :):

                        <----------
const arr = [2, 3, 4, 5, 6, 7, 8, 9]

The single value here is not an array with a single value in it. No, it means a standalone value. The elements in the array are applied to a supplied function callbackFn, the result of the function is used to apply the function to the next element. This continues on all the elements in the array till it ends, now the result of the function applied on the last element in the array is what is returned.

这里的单个值不是其中包含单个值的数组。 不,这意味着独立的价值。 数组中的元素将应用于提供的函数callbackFn ,函数的结果用于将函数应用于下一个元素。 这将继续对数组中的所有元素进行处理,直到结束为止,现在返回数组的最后一个元素所应用的函数的结果。

We are the ones to define the logic we want to be applied to each element in the array in the callbackFn function. The callbackFn function is passed params to let us get more control and access on the array.

我们是在callbackFn函数中定义要应用于数组中每个元素的逻辑的人。 callbackFn函数传递了参数,使我们可以对数组进行更多控制和访问。

  • previousValue: The previous value in the array.

    previousValue:数组中的上一个值。
  • currentValue: The current value in the index we are currently working on.

    currentValue:我们当前正在处理的索引中的当前值。
  • currentIndex: The current index of the array we are working on.

    currentIndex:我们正在处理的数组的当前索引。
  • array: The array we are working on.

    array:我们正在处理的数组。

In this code:

在此代码中:

const arr = [2, 3, 4, 5, 6, 7, 8, 9]const i = arr.reduceRight((pv, cv, ci) => {
return 2 * cv;
}, 90)

reduceRight will loop through the elements in the arr array. It will multiply each element by 2 and return it to b used on the next element in line. Here, pv is the previousValue, cv is the currentValue and ci is the currentIndex.

reduceRight将循环遍历arr数组中的元素。 它将每个元素乘以2,并将其返回给行中下一个元素使用的b。 在这里, pv是previousValue, cv是currentValue, ci是currentIndex。

Th initialValue allows us to set the initial/first value in the method. It is passed as the initial value of the previousValue arg in the callbackFn function.

initialValue允许我们在方法中设置初始值/第一个值。 它作为callbackFn函数中previousValue arg的初始值传递。

We have this:

我们有这个:

const arr = [2, 3, 4, 5, 6, 7, 8, 9]const i = arr.reduceRight((pv, cv, ci) => {
return 2 * cv
}, 90)

initialValue is set to be 90. When reduceRight starts, it will begin from 9, at that point cv the current value will be 90, the initial value we passed to be 90.

initialValue设置为90。当reduceRight开始时,它将从9开始,在那一点cv ,当前值将为90,我们传递的初始值为90。

Then after that cv will be the result of 2 * cv.

然后, cv将是2 * cv的结果。

To verify let’s log cv.

为了验证,让我们记录cv

const arr = [2, 3, 4, 5, 6, 7, 8, 9]const i = arr.reduceRight((pv, cv, ci) => {
log("previousValue: "+pv)
return 2 * cv
}, 90)previousValue: 90
previousValue: 18
previousValue: 16
previousValue: 14
previousValue: 12
previousValue: 10
previousValue: 8
previousValue: 6

If we do not specify an initialValue, the right-most element will be taken as the initial value, then the array will start at the next value downwards.

如果未指定initialValue,则将最右边的元素作为初始值,然后数组将从下一个向下的值开始。

const arr = [2, 3, 4, 5, 6, 7, 8, 9]const i = arr.reduceRight((pv, cv, ci) => {
return 2 * cv;
})

Like above, we have no initial value. The method will take 9 as the initial value and start from 8. So in element 8, the previous value will be 9.

像上面一样,我们没有初始值。 该方法将以9作为初始值并从8开始。因此,在元素8中,前一个值为9。

const arr = [2, 3, 4, 5, 6, 7, 8, 9]const i = arr.reduceRight((pv, cv, ci) => {
l("curentValue: " + cv + " previousValue: " + pv)
return 2 * cv;
})curentValue: 8 previousValue: 9
curentValue: 7 previousValue: 16
curentValue: 6 previousValue: 14
curentValue: 5 previousValue: 12
curentValue: 4 previousValue: 10
curentValue: 3 previousValue: 8
curentValue: 2 previousValue: 6

具有初始值的reduceRight (reduceRight with an initial value)

const arr = [2, 3, 4, 5, 6, 7, 8, 9]const i = arr.reduceRight((pv, cv, ci) => {
l("curentValue: " + cv + " previousValue: " + pv)
return cv + pv ;
}, 90)

Let’s take it piece by piece.

让我们一步一步来。

reduceRight will loop through the elements in the arr array starting from 9 down. When the reduceRight method is called. It sees an initialValue of 90, and it will start at 9.

reduceRight将从9开始向下遍历arr数组中的元素。 调用reduceRight方法时。 它的初始值是90,将从9开始。

At 9:

在9:

currentValue will be 9 currentIndex will be 7 , index ranges grow from left to right. starting at 0. So element 9 is at index 7. previousValue will be 90 (initialValue as set to be 90)

currentValue将是9 currentIndex将是7,索引范围从左到右增长。 从0开始。因此元素9在索引7处。previousValue将为90(initialValue设置为90)

reduceRight will call the callbackFn function. Params will be passed to it. pv will be 90, cv will be 9 and ci will be 7. In the callbackFn, pv 90 will be added to cv 9, the result will be 99, it will be returned and reduceRight moves to element 8.

reduceRight将调用callbackFn函数。 参数将传递给它。 pv将为90,cv将为9,ci将为7。在callbackFn中,将pv 90添加到cv 9,结果将为99,将被返回,并将reduceRight移至元素8。

At element 8:

在元素8:

currentValue will be 8 currentIndex will be 6, index ranges grow from left to right. starting at 0. So element 8 is at index 6. previousValue will be 99 (now it will no longer be the value of the initialValue, it will now be the value (result of 90 + 9) returned by the callbackFn when applied on element 9 the previous element)

currentValue将是8 currentIndex将是6,索引范围从左到右增长。 从0开始。因此元素8在索引6处。previousValue将为99(现在它将不再是initialValue的值,现在将是callbackFn应用于元素时返回的值(结果90 + 9 )。 9前一个元素)

reduceRight will call the callbackFn function. Params will be passed to it. pv will be 99, cv will be 8 and ci will be 6. In the callbackFn, pv 99 will be added to cv 8, the result will be 107, it will be returned and reduceRight moves to element 7.

reduceRight将调用callbackFn函数。 参数将传递给它。 pv将是99,cv将是8,ci将是6。在callbackFn中,pv 99将被添加到cv 8,结果将是107,它将被返回并且reduceRight移至元素7。

At element 7:

在元素7:

currentValue will be 7 currentIndex will be 5, index ranges grow from left to right. starting at 0. So element 7 is at index 5. previousValue will be 107 (result of 90 + 9 returned by the callbackFn when applied on element 8 the previous element)

currentValue将是7 currentIndex将是5,索引范围从左到右增长。 从0开始。因此元素7在索引5处。previousValue将为107(在元素8上的前一个元素上应用callbackFn返回的结果90 + 9 )

reduceRight will call the callbackFn function. Params will be passed to it. pv will be 107, cv will be 7 and ci will be 5. In the callbackFn, pv 107 will be added to cv 7, the result will be 114, it will be returned and reduceRight moves to element 6.

reduceRight将调用callbackFn函数。 参数将传递给它。 pv将为107,cv将为7,ci将为5。在callbackFn中,将pv 107添加到cv 7,结果将为114,将被返回,并将reduceRight移至元素6。

At element 6:

在元素6:

currentValue will be 6 currentIndex will be 4, index ranges grow from left to right. starting at 0. So element 6 is at index 4. previousValue will be 114 (result returned by the callbackFn when applied on element 7 the previous element)

currentValue将是6 currentIndex将是4,索引范围从左到右增长。 从0开始。因此元素6在索引4处。previousValue将为114(当在元素7上的前一个元素上应用callbackFn返回的结果)

reduceRight will call the callbackFn function. Params will be passed to it. pv will be 114, cv will be 6 and ci will be 4. In the callbackFn, pv 114 will be added to cv 6, the result will be 120, it will be returned and reduceRight moves to element 5.

reduceRight将调用callbackFn函数。 参数将传递给它。 pv将是114,cv将是6,ci将是4。在callbackFn中,pv 114将被添加到cv 6,结果将是120,将被返回并且reduceRight移至元素5。

Assignment: Complete the rest in the comments. Practice makes perfect. Completing will make you get hang of it and I assure you you will never forget how reduceRight works.

作业:完成评论中的其余部分。 实践使完美。 完成将使您无法胜任,并且向您保证,您将永远不会忘记reduceRight的工作原理。

没有initialValue (Without initialValue)

Let’s see when no initialValue is passed.

让我们看看何时没有传递initialValue。

const arr = [2, 3, 4, 5, 6, 7, 8, 9]const i = arr.reduceRight((pv, cv, ci) => {
return cv + pv ;
})

With no initialValue, element 9 will be the initial value. So reduceRight begins at element 8.

如果没有initialValue,则元素9将为初始值。 因此reduceRight从元素8开始。

At element 8:

在元素8:

currentValue will be 8 currentIndex will be 6, index ranges grow from left to right. starting at 0. So element 8 is at index 6. previousValue will be 9 (because we didn’t specify initialValue, so reduceRight will take the right-most element in the array, which is 9 here, to be the initialValue)

currentValue将是8 currentIndex将是6,索引范围从左到右增长。 从0开始。因此元素8在索引6处。previousValue将为9(因为我们未指定initialValue,所以reduceRight将采用数组中最右边的元素(此处为9)作为initialValue)。

The callbackFn will be called on the element 8, the pv will be 9, cv will be 8 and ci will be 6. The result of cv + pv (which is 8 + 9 == 17) will be returned and reduceRight moves to element 7.

callbackFn将在元素8上调用,pv将为9,cv将为8,ci将为6。将返回cv + pv(即8 + 9 == 17)的结果,并将reduceRight移动到元素7

At element 7:

在元素7:

currentValue will be 7 currentIndex will be 5, index ranges grow from left to right. starting at 0. So element 7 is at index 5. previousValue will be 17 (result returned by the callbackFn when applied on element 8 the previous element)

currentValue将是7 currentIndex将是5,索引范围从左到右增长。 从0开始。因此元素7在索引5处。previousValue将为17(当应用于前一个元素的元素8时callbackFn返回的结果)

The callbackFn will be called on the element 7, the pv will be 17, cv will be 7 and ci will be 5. The result of cv + pv (which is 7 + 17 == 24) will be returned and reduceRight moves to element 6.

callbackFn将在元素7上调用,pv将为17,cv将为7,ci将为5。将返回cv + pv的结果(即7 + 17 == 24),并将reduceRight移动到元素6。

At element 6:

在元素6:

currentValue will be 6 currentIndex will be 4, index ranges grow from left to right. starting at 0. So element 6 is at index 4. previousValue will be 24 (result returned by the callbackFn when applied on element 7 the previous element)

currentValue将是6 currentIndex将是4,索引范围从左到右增长。 从0开始。因此元素6在索引4处。previousValue将为24(当应用于上一个元素的元素7时callbackFn返回的结果)

The callbackFn will be called on this element 6, the pv will be 24, cv will be 6 and ci will be 4. The result of cv + pv (which is 6 + 24 == 30) will be returned and reduceRight moves to element 5.

将在此元素6上调用callbackFn,pv将为24,cv将为6,ci将为4。将返回cv + pv的结果(即6 + 24 == 30),并将reduceRight移动到元素5,

Assignment: Do the rest in the comments.

作业:在评论中其余内容。

callbackFn不返回任何东西时会发生什么? (What happens when the callbackFn doesn't return anything?)

We know that the result of the callbackFn applied to an element is passed to the callbackFn as previousValue arg when being applied to the next element. So we know it must return something.

我们知道,应用于元素的callbackFn的结果在应用于下一个元素时会作为previousValue arg传递给callbackFn。 所以我们知道它必须返回一些东西。

Now, if the callbakcFn doesn’t return anything, the loop through the elements in the array will be done but the previousValue arg will be undefined on each element. With that, the result of the method will be undefined.

现在,如果callbakcFn不返回任何内容,则将完成遍历数组中元素的循环,但在每个元素上未定义previousValue arg。 这样,该方法的结果将是不确定的。

const arr = [2, 3, 4, 5, 6, 7, 8, 9]const i = arr.reduceRight((pv, cv, ci) => {
const result = pv + cv
l("curentValue: " + cv + " previousValue: " + pv + " currentIndex: "+ci+ " Result: "+ result)
}, 90)l(i)

The log:

日志:

curentValue: 9 previousValue: 90 currentIndex: 7 Result: 99
curentValue: 8 previousValue: undefined currentIndex: 6 Result: NaN
curentValue: 7 previousValue: undefined currentIndex: 5 Result: NaN
curentValue: 6 previousValue: undefined currentIndex: 4 Result: NaN
curentValue: 5 previousValue: undefined currentIndex: 3 Result: NaN
curentValue: 4 previousValue: undefined currentIndex: 2 Result: NaN
curentValue: 3 previousValue: undefined currentIndex: 1 Result: NaN
curentValue: 2 previousValue: undefined currentIndex: 0 Result: NaN
undefined

See, pv is undefined on every element and the final result i returned is undefined.

看到,pv在每个元素上都是不确定的, i返回的最终结果也是不确定的。

reduceRight的回报是什么? (What do reduceRight returns?)

reduceRight returns the result of the callbackFn when applied on the last element in the array.

当应用在数组的最后一个元素上时,reduceRight返回callbackFn的结果。

const arr = [2, 3, 4, 5, 6, 7, 8, 9]const i = arr.reduceRight((pv, cv, ci) => {
const result = pv + cv
l("curentValue: " + cv + " previousValue: " + pv + " currentIndex: " + ci + " Result: " + result)
return result;
}, 90)l(i)

The output:

输出:

curentValue: 9 previousValue: 90 currentIndex: 7 Result: 99
curentValue: 8 previousValue: 99 currentIndex: 6 Result: 107
curentValue: 7 previousValue: 107 currentIndex: 5 Result: 114
curentValue: 6 previousValue: 114 currentIndex: 4 Result: 120
curentValue: 5 previousValue: 120 currentIndex: 3 Result: 125
curentValue: 4 previousValue: 125 currentIndex: 2 Result: 129
curentValue: 3 previousValue: 129 currentIndex: 1 Result: 132
curentValue: 2 previousValue: 132 currentIndex: 0 Result: 134
134

See, reduceRight returns 134, the value of the application of the callbackFn on the last element 2 in the arr array.

参见,reduceRight返回134,即在arr数组中最后一个元素2上的callbackFn的应用程序的值。

So what reduceRight returns depends on what the callbackFn returns. It can be of any data type. It depends on the user.

因此,reduceRight返回的内容取决于callbackFn返回的内容。 它可以是任何数据类型。 这取决于用户。

我们的reduceRight实施 (Our reduceRight implementation)

With what we have seen how reduceRight works let’s use our knowledge of it to write our implementation:

通过我们已经看到的reduceRight的工作原理,让我们利用对它的了解编写实现:

// This overrides the original Array#reduceRight to add ours in place. Calls to Array#reduceRight after this will call our implementation.
Array.prototype.reduceRight = function(callbackFn, initialValue) {
/**
* 'callbackFn' holds the callback function of the method.
* 'initialValue' holds the first value passed to the method
*/ // make sure the types are correct before we proceed.
if(typeof callbackFn !== 'function') {
throw Error("the 'callbackFn' must be a function")
}
if(this === null || this === undefined) {
throw Error("this should not be null or undefined")
} // this holds the elements in the array
// we assigned it to a local variable so we can modify and reassign it because this is un-assignable
var data = this // holds the results of previous 'callbackFn' invocation
var accumulator // we check if something is in the array
if (data.length > 0) { // check for undefined initial value i.e when initial value is not passed.
if (initialValue === undefined) { // if the elements in the array is one we just return it.
if (data.length == 1) {
return data[0]
} // because the initial value is not set, the right-most element becomes the initial value
initialValue = data[data.length - 1] // the right-most that just became the initial value is removed from the array, so reduceRight starts from the next element down inline.
data = data.slice(0, data.length - 1)
} // the initial value is assigned to the accumulator because the accumulator will start from the initial value to build-up
accumulator = initialValue // we loop through the array. We start from the right-most element downwards.
for (var index = data.length - 1; index >= 0; index--) { // the cuurent element in the array
var element = data[index]; // for each element, the 'callbackFn' is called. 'accumulator' will be the previous value, 'element' the current value and 'index' the current index are passed to the 'callbackFn'. The result is assigned back to 'accumulator', thus 'accumulator' always holds the previous value.
accumulator = callbackFn(accumulator, element, index)
} // the build up of the 'callbackFn' invocations on each element stored in the accumulator is returned.
return accumulator
}
}

This our implementation depicts this:

我们的实现描述如下:

Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result and is provided as an argument in the next call to the callback function.

为数组中的所有元素以降序调用指定的回调函数。 回调函数的返回值是累加结果,并在下一次对回调函数的调用中作为参数提供。

Assignment: Write your implementation. Wanna see the brilliant algorithm you can come up with. Make to perf test it too, I’ll also want to see the benchmark results.

作业:编写您的实现。 想知道您能想到的出色算法。 也要进行性能测试,我还要查看基准测试结果。

用法:角形 (Usage: Angular)

Angular uses reduceRight to chain up HttpInterceptors.

Angular使用reduceRight链接HttpInterceptor。

/**
* An injectable `HttpHandler` that applies multiple interceptors
* to a request before passing it to the given `HttpBackend`.
*
* The interceptors are loaded lazily from the injector, to allow
* interceptors to themselves inject classes depending indirectly
* on `HttpInterceptingHandler` itself.
* @see `HttpInterceptor`
*/
@Injectable()
export class HttpInterceptingHandler implements HttpHandler {
private chain: HttpHandler|null = null; constructor(private backend: HttpBackend, private injector: Injector) {} handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
if (this.chain === null) {
const interceptors = this.injector.get(HTTP_INTERCEPTORS, []);
this.chain = interceptors.reduceRight(
(next, interceptor) => new HttpInterceptorHandler(next, interceptor), this.backend);
}
return this.chain.handle(req);
}
}

Here, Angular gets the HttpInterceptors array and sets it in, interceptors. See, the callbackFn returns an instance of HttpInterceptorHandler passing next and interceptor as its constructor params. The next is previousValue and interceptor is the currentValue. this.backend is the initialValue.

在这里,Angular获取HttpInterceptors数组并将其设置为interceptors 。 看到, callbackFn返回HttpInterceptorHandler的实例,该实例将nextinterceptor作为其构造函数参数传递。 next是previousValue, interceptor是currentValue。 this.backend是initialValue。

After the last invocation on the last interceptor in the array, the result will be set to the chain variable.

在数组中最后一个拦截器上的最后一次调用之后,结果将被设置为链变量。

With how HttpHandlers and HttpInterceptors are implemented in Angular the above reduceRight forms a chain of interceptors and handlers.

通过在Angular中实现HttpHandlers和HttpInterceptors的方式,上述reduceRight构成了一系列拦截器和处理程序。

结论 (Conclusion)

I hope that sealed it. With this, you will no longer be rushing to open that Google search bar to type in “reduceRight js” whenever you come across reduceRight or wanna use it because now, you know how it works.

我希望将其密封。 有了它,您将不再会急于打开Goog​​le搜索栏以在遇到reduceRight或想要使用它时键入“ reduceRight js”,因为现在您知道它是如何工作的。

Make sure you do all my assignments. I will be watching the comments section.

确保您完成了我所有的任务。 我将观看评论部分。

Thanks for stopping by my little corner of the web. I think you’ll love my email newsletter about programming advice, tutoring, tech, programming and software development. Just sign up below:

感谢您停在我的网络小角落。 我想您会喜欢我的电子邮件通讯,其中涉及编程建议,辅导,技术,编程和软件开发。 只需在下面注册:

Follow me on Twitter.

Twitter上 关注我

翻译自: https://medium.com/dev-proto/how-it-works-array-reduceright-f7dfbd32cc59

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值