@@ -19,10 +19,36 @@ const {
1919// `uncurryThis` is equivalent to `func => Function.prototype.call.bind(func)`.
2020// It is using `bind.bind(call)` to avoid using `Function.prototype.bind`
2121// and `Function.prototype.call` after it may have been mutated by users.
22- const { bind, call } = Function.prototype;
22+ const { apply, bind, call } = Function.prototype;
2323const uncurryThis = bind.bind(call);
2424primordials.uncurryThis = uncurryThis;
2525
26+ // `applyBind` is equivalent to `func => Function.prototype.apply.bind(func)`.
27+ // It is using `bind.bind(apply)` to avoid using `Function.prototype.bind`
28+ // and `Function.prototype.apply` after it may have been mutated by users.
29+ const applyBind = bind.bind(apply);
30+ primordials.applyBind = applyBind;
31+
32+ // Methods that accept a variable number of arguments, and thus it's useful to
33+ // also create `${prefix}${key}Apply`, which uses `Function.prototype.apply`,
34+ // instead of `Function.prototype.call`, and thus doesn't require iterator
35+ // destructuring.
36+ const varargsMethods = [
37+ // 'ArrayPrototypeConcat' is omitted, because it performs the spread
38+ // on its own for arrays and array-likes with a truthy
39+ // @@isConcatSpreadable symbol property.
40+ 'ArrayOf',
41+ 'ArrayPrototypePush',
42+ 'ArrayPrototypeUnshift',
43+ // 'FunctionPrototypeCall' is omitted, since there's 'ReflectApply'
44+ // and 'FunctionPrototypeApply'.
45+ 'MathHypot',
46+ 'MathMax',
47+ 'MathMin',
48+ 'StringPrototypeConcat',
49+ 'TypedArrayOf',
50+ ];
51+
2652function getNewKey(key) {
2753 return typeof key === 'symbol' ?
2854 `Symbol${key.description[7].toUpperCase()}${key.description.slice(8)}` :
@@ -49,7 +75,13 @@ function copyPropsRenamed(src, dest, prefix) {
4975 if ('get' in desc) {
5076 copyAccessor(dest, prefix, newKey, desc);
5177 } else {
52- ReflectDefineProperty(dest, `${prefix}${newKey}`, desc);
78+ const name = `${prefix}${newKey}`;
79+ ReflectDefineProperty(dest, name, desc);
80+ if (varargsMethods.includes(name)) {
81+ ReflectDefineProperty(dest, `${name}Apply`, {
82+ value: applyBind(desc.value, src),
83+ });
84+ }
5385 }
5486 }
5587}
@@ -61,10 +93,18 @@ function copyPropsRenamedBound(src, dest, prefix) {
6193 if ('get' in desc) {
6294 copyAccessor(dest, prefix, newKey, desc);
6395 } else {
64- if (typeof desc.value === 'function') {
65- desc.value = desc.value.bind(src);
96+ const { value } = desc;
97+ if (typeof value === 'function') {
98+ desc.value = value.bind(src);
99+ }
100+
101+ const name = `${prefix}${newKey}`;
102+ ReflectDefineProperty(dest, name, desc);
103+ if (varargsMethods.includes(name)) {
104+ ReflectDefineProperty(dest, `${name}Apply`, {
105+ value: applyBind(value, src),
106+ });
66107 }
67- ReflectDefineProperty(dest, `${prefix}${newKey}`, desc);
68108 }
69109 }
70110}
@@ -76,10 +116,18 @@ function copyPrototype(src, dest, prefix) {
76116 if ('get' in desc) {
77117 copyAccessor(dest, prefix, newKey, desc);
78118 } else {
79- if (typeof desc.value === 'function') {
80- desc.value = uncurryThis(desc.value);
119+ const { value } = desc;
120+ if (typeof value === 'function') {
121+ desc.value = uncurryThis(value);
122+ }
123+
124+ const name = `${prefix}${newKey}`;
125+ ReflectDefineProperty(dest, name, desc);
126+ if (varargsMethods.includes(name)) {
127+ ReflectDefineProperty(dest, `${name}Apply`, {
128+ value: applyBind(value),
129+ });
81130 }
82- ReflectDefineProperty(dest, `${prefix}${newKey}`, desc);
83131 }
84132 }
85133}
0 commit comments