Hacker News new | past | comments | ask | show | jobs | submit login
A long list of (advanced) JavaScript questions, and their explanations (github.com/lydiahallie)
148 points by redbell 7 months ago | hide | past | favorite | 43 comments



Cannot be complete without a reference to Wat

[https://www.destroyallsoftware.com/talks/wat]


Also, my favorite collection of JS weirdness, “Return true to win”: https://alf.nu/ReturnTrue?world=true&level=id


What is supposed to be happening here? I keep getting a popup (on Orion browser) saying "Orion cannot open the page because the address is invalid." on every interaction, and nothing happens except it counts the characters of my input.


It is a known issue in Orion, tracked here https://orionfeedback.org/d/7856-cannot-open-this-page-becau...


Thanks -- assumed it was an issue on the app's side.

Also, that was fast. Do y'all have a script checking for Kagi/Orion mentions on HN?


I use the excellent https://f5bot.com


This is a weird mix of stuff I would consider basic and stuff that no one should ever need to worry about.


Besides yet another "damn, Javascript is whack" article, I thought a lot of the details were actually really interesting, and stuff that I either outright didn't know or had just forgotten because I use TypeScript and a lot of these thing would make the TS compiler complain.

For example, I can't remember the last time I used the `var` keyword, and I had either forgotten or never really realized it had subtly different semantics compared to `let` and `const`, e.g. with respect to hoisting rules.


Which in this case most folks have moved on to let and const. But tons of code in the wild is still sprinkled with var. If you’re mostly working greenfield JavaScript, you can ignore a lot of the warts and have a pretty good experience. If you’re working on a lot of legacy stuff you’ll see mixed use of var and let and it’s quite helpful to understand the differences more fully.


I'd never call myself a JS dev but have used it to develop web pages on the side. this list shows me how little I really understand the more intimate details of JS. I'd personally love to see a variation of this for C/C++/C#.

And in all fairness, "stuff no one should ever need to worry about" is prime interview material for jobs. Though there's so many formats of technical interviews you never really know.


https://cppquiz.org contains a list of similar questions in C++.


perfect, that was exactly what I was looking for. Thanks!


> And in all fairness, "stuff no one should ever need to worry about" is prime interview material for jobs.

In reality, when I've seen this:

1. Shitty companies will ask you esoteric details like this that aren't relevant to your job, in which case you should avoid them anyway. It's usually from immature devs that just go down a laundry list of stuff just because it's "easier to grade". Note I'm not referring to Javascript "weirdness" that may seem esoteric but is actually pretty important to know. For example, anyone who has been programming in javascript for more than a hot minute should know `typeof null === 'object'`, because (a) nearly everyone hits this as a bug at least once and thinks "that's nutty", and then (b) if you don't know this you will be likely to write bugs in your code.

2. This also doesn't apply if you're interviewing for a job where you need to know those esoteric details, like the other commenter who replied who wrote a transpiler. But if you're just, say, a front-end web dev, yeah asking some of the nuttier details (especially all of the inherent type conversion rules) is sign of a bad company IMO.


>Shitty companies will ask you esoteric details like this that aren't relevant to your job, in which case you should avoid them anyway.

I sure do wish I had the luxury to do that. How the times have changed so quickly.

That's pretty much why I detest the leetcode stuff that pops up even in games interviews. I'm going to be digging into decades old poorly documented legacy code to provide custom tooling for a studio's workflow. Why the hell do I need to know how to make NxN Bingo solver in Log(N) time on the fly? I guess if you gave me 20 minutes to refresh myself on dynamic progamming I could do it, but I made the "mistake" of studdying Unreal Engine/C++ trivia instead (which I've also had on other interviews), as well as real questions like what impacts and tasks I was doing at other studios.

But it's a circus out there and I just have to put on the makeup. I'm preparing long term to not have to deal with this, but I just need another 3 years or so minimum to stabilize myself and prepare my plans.


This. If this were part of a coding interview, I'd pass on the company. Don't do this. This is also why real developers use tests and actually try things before shipping them, as almost all of these fictional scenarios should be caught ahead of time by any reasonably sane tests.


FWIW, I failed a few of these and built an entire full-stack JS framework (CLI, front-end, and back-end) [1]. Does this stuff come up? Yes. But knowing the answers to trivia that only seldom come up is a terrible way to evaluate talent.

[1] https://cheatcode.co/joystick


I sampled about 20 questions and got them all right. I guess it helps to be author of a compile-to-JavaScript language. That gives way more knowledge about the tricky spec corner cases. Knowing these things is less useful for a JavaScript practitioner.


And this is why there's so much interest in transpiling to Javascript. Rather than commit any time to understanding these often poorly designed semantics, automate that complexity away with a better designed language.


JavaScript is very well designed for backwards compatibility. Many of these examples are showing off old features that were intentionally changed in order to make more sense next to the new features that replaced them. But presenting both next to each other and highlighting a difference in behavior makes the language look inconsistent.


It's a tragedy when you think about how many millions (billions?) of man hours have been wasted on javascript because it's the only native scripting language of the browser. Even more tragic is that the original plan was to make scheme the language of the browser.


Well, now you can compile scheme to run on the browser with Hoot (Guile scheme to WASM): https://spritely.institute/hoot/


There's an experimental Racket to JavaScript compiler too: https://docs.racket-lang.org/racketscript/index.html

Ooo, there's more: https://github.com/jashkenas/coffeescript/wiki/List-of-langu...


If you find yourself using a language where you need to answer questions like this, are these really the questions worth asking?


95% of these questions are irrelevant, even if you never develop in anything but this language. They tell us nothing. It’s not a useful set of questions for any purpose and there’s no insight here


Number 17 just made me understand why Prisma.queryRaw`template literal string` works without (). My first thought when I saw the question was wtf is this. I'll add it to the list of things I'll probably personally never need to write.


These are fun questions and demonstrate interesting behaviours in JavaScript. Something I noticed compared to a decade ago when I anxiously thought I needed to know all these kinds of quirks: they’re pretty much all made irrelevant by using TypeScript.


It didn't help that when you were searching for common interview questions these are the ones that kept coming up.


How come

{a:1}["a"] evaluates to ["a"]

but ({a:1}["a"]) evaluates to 1?


I think this is because {a:1} is a cleverly disguised block statement with a label named 'a', followed by the expression 1.

It looks bad, but it never comes up in practice because {a:1} is only parsed as a block if it's at the start of a line, which it never would be.


Very helpful!


    { // start block statement
      a: // labeled statement [1]
      1  // expression statement
    } // end block statement
    [ // start array literal
      “a” // string value
    ] // end array literal

vs.

    ( // start expression statement
      { // start object literal
        a: // object literal key
        1  // expression statement
      } // end object literal statement
      [ // begin subscript property access
          “a” // string (property key)
      ] // end subscript property access
    ) // end expression
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... versus

Edit: fixed second example (it did not match the parent comment), changed some verbiage


Very helpful!


That’s not true. If it appears true it’s because you’re using a repl that treats the first part as a separate statement and returns the value of the second part as the most recent statement, but there’s literally nowhere you can encounter the behaviour you described in a JavaScript program


It is true. If you paste it into TS on its own line, even inside a function, TS will flag 'a' as an unused label.


That’s not the claim that was made. That code can not be evaluated to produce that value by any rules of the language. It can only be evaluated to produce that result by a repl which is parsing it as statements and then evaluating the most recent statement, in a non-standard way, but in the language itself two consecutive statements do not have a defined evaluation, and in any context where it is being evaluated it would gramatically need to be parsed as a single expression instead.

If that’s not correct you can provide a counter example


console.log(eval('{a:1}["a"]'))


Number 14 still confuses me. The base object does have prototypes but can traverse the prototype chain? My brain seizes.


Number 14 is just wrong, or rather its explanation is wrong.

It’s technically correct: not all objects have prototypes (you can trivially make an object without one or remove it from an existing object).

The rest of that “answer” is just nonsense: there is no magic look up of a magic basic object. The default prototype of an object is prototype property of the creation function (e.g Object, String, MyFunction, …), and the top of the chain is Objecy.prototype unless explicitly set to something else.

There’s no magic, and I don’t know how the author got their particular explanation.


Anybody else experience mobile Safari crashing on this github repo?

“A problem repeatedly occurred…”


At first I thought maybe this was showing that I'm way less good at JS than I thought I was. But after thinking about it some more, I'm still fine at JS. All my sites work just fine. My clients are seemingly happy with them and I get paid for it. Instead, I'm just not good at the weird edge cases that nobody actually ever hits, which is what all these questions are!

(that being said, I do roll my eyes every time I have to clear out an array by doing myarray.length = 0 instead of myarray = []. JS is such a silly language sometimes.)


> I do roll my eyes every time I have to clear out an array by doing myarray.length = 0 instead of myarray = []. JS is such a silly language sometimes.

In your example, if myarray was the only reference to your array, it would likely not matter which way you do it. Clear the original array, or reassign the variable to point to a new empty array.

It becomes important when you have another reference to the same array.

That's not just a JavaScript thing. Any language where [] creates a new array/list, and the = operator copies a reference will have the same behavior.

Take Python for example:

  >>> a = [3,2,1]
  >>> b = a
  >>> a
  [3, 2, 1]
  >>> b
  [3, 2, 1]
  >>> a = []
  >>> a
  []
  >>> b
  [3, 2, 1]
  >>>
  
  >>> a = [3,2,1]
  >>> b = a
  >>> a
  [3, 2, 1]
  >>> b
  [3, 2, 1]
  >>> a.clear()
  >>> a
  []
  >>> b
  []
  >>>
Or Ruby:

  irb(main):001:0> a = [3,2,1]
  => [3, 2, 1]
  irb(main):002:0> b = a
  => [3, 2, 1]
  irb(main):003:0> a
  => [3, 2, 1]
  irb(main):004:0> b
  => [3, 2, 1]
  irb(main):005:0> a = []
  => []
  irb(main):006:0> a
  => []
  irb(main):007:0> b
  => [3, 2, 1]
  irb(main):008:0>
  
  irb(main):009:0> a = [3,2,1]
  => [3, 2, 1]
  irb(main):010:0> b = a
  => [3, 2, 1]
  irb(main):011:0> a
  => [3, 2, 1]
  irb(main):012:0> b
  => [3, 2, 1]
  irb(main):013:0> a.clear()
  => []
  irb(main):014:0> a
  => []
  irb(main):015:0> b
  => []
  irb(main):016:0>
And JavaScript to compare with the other two:

  > a = [3,2,1]
  (3) [3, 2, 1]
  > b = a
  (3) [3, 2, 1]
  > a = []
  []
  > a
  []
  > b
  (3) [3, 2, 1]

  > a = [3,2,1]
  (3) [3, 2, 1]
  > b = a
  (3) [3, 2, 1]
  > a.length = 0
  0
  > a
  []
  > b
  []
Python and Ruby do have that nice clear() method instead of having to set .length to 0, but the underlying semantics are the same in all three languages.


Love it! Thanks for sharing.


Gosh what a terrible language.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: