From 04e752738c7ca80d5bae018f5dac94112530976a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=C2=A0S=2E=20Choi?= Date: Thu, 30 Sep 2021 16:27:59 -0400 Subject: [PATCH] =?UTF-8?q?explainer=20=C2=A7=C2=A0Node:=20Use=20Function.?= =?UTF-8?q?apply;=20other=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 49 +++++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index d304ae2..a711022 100644 --- a/README.md +++ b/README.md @@ -189,11 +189,12 @@ ArrayPrototypeFindIndex: uncurryThis(Array.prototype.findIndex), ArrayPrototypeLastIndexOf: uncurryThis(Array.prototype.lastIndexOf), ArrayPrototypePop: uncurryThis(Array.prototype.pop), ArrayPrototypePush: uncurryThis(Array.prototype.push), -ArrayPrototypePushApply: UncurryThisStaticApply +ArrayPrototypePushApply: applyBind(Array.prototype.push), ArrayPrototypeReverse: uncurryThis(Array.prototype.reverse), ``` -…and so on, where `uncurryThis` is `Function.bind.bind(Function.call)` -(also called [“call-binding”][call-bind]). +…and so on, where `uncurryThis` is `Function.prototype.call.bind` +(also called [“call-binding”][call-bind]), +and `applyBind` is the similar `Function.prototype.apply.bind`. [call-bind]: https://npmjs.com/call-bind @@ -205,11 +206,10 @@ using the `uncurryThis` helper function. The result is that code that uses these global intrinsic methods, like this code adapted from [node/lib/internal/v8_prof_processor.js][]: ```js - // specifier is a string. + // `specifier` is a string. const file = specifier.slice(2, -4); -``` -… -```js + + // Later… if (process.platform === 'darwin') { tickArguments.push('--mac'); } else if (process.platform === 'win32') { @@ -222,27 +222,25 @@ like this code adapted from [node/lib/internal/v8_prof_processor.js][]: // Note: This module assumes that it runs before any third-party code. const { ArrayPrototypePush, + ArrayPrototypePushApply, ArrayPrototypeSlice, StringPrototypeSlice, } = primordials; -``` -… -```js + + // Later… const file = StringPrototypeSlice(specifier, 2, -4); -``` -… -```js + + // Later… if (process.platform === 'darwin') { ArrayPrototypePush(tickArguments, '--mac'); } else if (process.platform === 'win32') { ArrayPrototypePush(tickArguments, '--windows'); } - ArrayPrototypePush(tickArguments, - ...ArrayPrototypeSlice(process.argv, 1)); + ArrayPrototypePushApply(tickArguments, ArrayPrototypeSlice(process.argv, 1)); ``` This code is now protected against prototype pollution by accident and by adversaries -(e.g., `delete Array.prototype.push`). +(e.g., `delete Array.prototype.push` or `delete Array.prototype[Symbol.iterator]`). However, this protection comes at two costs: 1. These [uncurried wrapper functions sometimes dramatically reduce performance][#38248]. @@ -262,22 +260,21 @@ without worrying about `Function.prototype.call` mutation: ```js // Note: This module assumes that it runs before any third-party code. +const $apply = Function.prototype.apply; const $push = Array.prototype.push; const $arraySlice = Array.prototype.slice; const $stringSlice = String.prototype.slice; -``` -… -```js - const file = specifier->stringSlice(2, -4); -``` -… -```js + + // Later… + const file = specifier->$stringSlice(2, -4); + + // Later… if (process.platform === 'darwin') { - tickArguments->push('--mac'); + tickArguments->$push('--mac'); } else if (process.platform === 'win32') { - tickArguments->push('--windows'); + tickArguments->$push('--windows'); } - tickArguments->push(...process.argv->slice(1)); + $push->$apply(tickArguments, process.argv->$arraySlice(1)); ``` Performance has improved, and readability has improved.