Skip to content

Conversation

@lquixada
Copy link
Contributor

@lquixada lquixada commented Jan 21, 2021

What is the purpose of this pull request?

  • Documentation update
  • Bug fix
  • New feature
  • Other, please explain:

What changes did you make? (provide an overview)

Added thisArg to Header's forEach method and header parameter on its callback.

Which issue (if any) does this pull request address?

#1072

Is there anything you'd like reviewers to know?

There's an unrelated lint issue on src/request.js that's breaking the CI checks.

@lquixada lquixada marked this pull request as ready for review January 21, 2021 00:22
src/headers.js Outdated
}

forEach(callback) {
forEach(callback, thisArg) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
forEach(callback, thisArg) {
forEach(callback, thisArg = undefined) {

This allows headers.forEach.length === 1, which matches browsers.

Copy link
Contributor Author

@lquixada lquixada Jan 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm a couple of things here:

  1. I can add that for extra clarity but the end result feels the same as thisArg will be undefined when headers.forEach.length === 1 anyways.
  2. To match browsers, the default value would be a global object such as window. On node, I guess global would do the job. Try this: [1].forEach(function () { console.log(this === global) })

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add that for extra clarity

The result indeed is the same inside forEach, but the = undefined is essential to get the correct .length property. Try

console.log(({ f(a, b) {} }).f.length);
console.log(({ f(a, b = undefined) {} }).f.length);

You will see that the first statement prints 2, while the second prints 1. We want the second behavior for forEach, and that's why you should add it. But indeed, the expected behavior is that if thisArg is not supplied, then it defaults to undefined.

By the way, the .length property of the forEach method is defined in the Web IDL standard, see "define the iteration methods" step 2.4.4.

To match browsers, the default value would be a global object such as window.

That's not quite right. In browsers, the default value is window only if we are not in strict mode:

image

Our test environments are all strict mode, but you can run Reflect.apply(function() { console.log(this); }, undefined, []) in the Node.js REPL (which is sloppy by default) to see that this is actually global in Node.js too.

All this is to say, you don't have to do anything special to get the global object behavior. (In fact, you cannot do anything here to replicate that in pure JavaScript, since there's no easy way of detecting whether a function is strict or sloppy.)

If you're interested in finding where this behavior is specified, it's in the ECMAScript standard, within OrdinaryCallBindThis abstract operation's steps 5–6.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @TimothyGu ! Thanks for that! It was very informative. All suggestions are committed now. Let me know if there's anything else I should do.

Btw, there's just a lint issue going on that I'm not able to fix. :/

const thisArg = {};
headers.forEach(function () {
expect(this).to.equal(thisArg);
}, thisArg);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also test the this value where thisArg is not supplied?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure! waiting for considerations on #1074 (comment).

@TimothyGu
Copy link
Collaborator

See https://github.com/node-fetch/node-fetch/blob/master/src/request.js#L85. You could add a comment to ignore the check, like

// eslint-disable-next-line no-eq-null, eqeqeq

@lquixada
Copy link
Contributor Author

See https://github.com/node-fetch/node-fetch/blob/master/src/request.js#L85. You could add a comment to ignore the check, like

// eslint-disable-next-line no-eq-null, eqeqeq

done! 👍

Copy link
Collaborator

@TimothyGu TimothyGu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I think someone else has to review this though.

Copy link
Member

@xxczaki xxczaki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

@tekwiz tekwiz merged commit 6ee9d31 into node-fetch:master Jan 26, 2021
@tekwiz tekwiz linked an issue Jan 26, 2021 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Header.forEach inconsistent with standard fetch API

4 participants