mindstalk: (angry sky)
New Job has me learning JS and Node.js. I have learned that some of my earlier complaints (see tag) have been improved by later developments (or ones extant at the time that I hadn't found.) Like 'var' variables have function scope (useful concept; I think it applies to Python), but you can get block scope (One True Way) by using 'let' instead. I don't think I knew that simply assigning to an undeclared variable creates a global (dear gods) but JS borrowed 'use strict'; from Perl, which shuts that off.

JS strikes me as a shitty half-assed core language which is trying to grow its way into respectability. Unfortunately it has 25 years of shitty web code to have to be backwardly compatible with.

No wonder there are multiple languages to use instead, that compile down into JS.

Today I accidentally discovered another WTF.

> l=[1,2,3]
[ 1, 2, 3 ]
> for (v in l) console.log(typeof(v));
string
string
string
undefined
> for (v in l) console.log(v);
0
1
2


So in a way this makes sense. "for in" iterates over the properties/keys of an object, which for an Object (dictionary-ish) are names. The properties of an Array are numbers, but in a 'for in' context, they could be strings.

OTOH, stripped of rationalization: the indices of an array are numeric, and yet they're strings in this iteration case. ffffuuuuu.

Of course, JS coerces between numbers and strings at least as fluidly as Perl does.

I found this behavior by accident, I was printing 'v[0]' thinking I was using 'for of" (which iterates over the values of an Array) when I wasn't, and I got numbers rather than letters or 'undefined', which is what you get if you try

> n=4
4
> n[0]
undefined
mindstalk: (Default)
I was looking at my 'programming' tag posts and found a bunch of 3 years ago, complaining about odd features of JavaScript. I kind of remember them now, but if you'd asked me yesterday if I'd ever taught myself JavaScript I would have said 'no', not remembering doing so.

I was prompted by an interviewer having looked at this blog. I wonder what he thought about my saying I hadn't taught myself JS...
mindstalk: (angry sky)
I've started studying JavaScript a bit, as you might guess from recent posts. It's struck me as a mix of Perl, Python, and crack. It's got some neat things, especially in comparison to one language or the other. And it's got lots of... wtf things.

+: exponentiation operator; nested arrays and objects (dictionaries) (without Perl's references); first class functions and lambdas and closures, including nested functions (unlike Perl); Perl-like push/pop/shift/unshift array operators (but what's the performance?); consistent 'valueOf' and 'toString' methods; JSON; multiple kinds of for loops; Perl style labeled break and continue; some convenient conversions (but see below); nice Date methods.

-: oh boy.

* JSON stringifies nested structures nicely, but simple output doesn't: [1, [2,3]] outputs as [1, 2, 3].
* (object1 == object2) is always false, no matter the underlying values. This holds for arrays and Date objects too. Nothing like Python's structural equality, or even that of STL containers.
** But you can do *inequality* comparison: ([1,2,3] < [2,2,3]) == true.
* strings take negative indices a la Python, but arrays don't. [2020 edit: what was I thinking? string.slice can take negative indices, but character access via [] doesn't. And array.slice also takes negative.]
* there's a typeof operator, but it just says 'object' for arrays.
* "5"+2 == "52" (convert 2 to "2", concatenate), but "5"-2 == 3 (convert "5" to 5, subtract.) And no Python string multiplier like "a"*2 == "aa".
** As Avi noted, it gets even weirder given that the values could be hidden in a variable. a+2=="52", a-2==3
* [1,2]+[3,4] doesn't concatenate arrays, doesn't add by element, doesn't give a type error, but gives... "1,23,4" (turn arrays into strings, concatenate without delimiter.)

My friend Mark linked me to https://www.destroyallsoftware.com/talks/wat which gives some more:
* []+{} == [object Object]
Ok, addition is commutative, right?
{}+[] == 0
And for luck: {}+{} == NaN
As above, []+[] == ""
** Actually, on playing with typeof, I think those are actually all strings. "[object Object]", "0", "NaN". OTOH, {}+[4]+5 == 9 (but typeof string)
**
>>> 5+{}+[4]
5[object Object]4 // because of course it does
*
return
  x;

turns into
 return;
 x;



* All numbers are 64-bit floats; you can still bitshift them, but as integers, so 5.2 << 2 == 20. This makes more sense when I remembered that floats are weird, not integers+fractions, so a simple bitshift of the fraction wouldn't make sense.
mindstalk: (Default)
A bit after writing the previous post on shadowing variables in JavaScript, I came across this page on hoisting. JavaScript re-writes your code so that declarations but not initializations to the top of current scope, meaning the script or function[1]. So

console.log(a);
var a=5;


turns into

var a;
console.log(a);
a=5;


Put that way, it's clear why the problem happens, if not why the language was designed this way.

Does the same thing happen in Python? Searching did not get clear results. I saw pages contrasting JavaScript with Python, which doesn't even *have* declarations. OTOH, the same behavior occurs. So... I dunno.

[1] JavaScipt does not have block scoping the way C and Perl[2] do; scopes are delimited by curly braces, but random curly braces do nothing to isolate variables.

{ a=5; }
console.log(a);


will work just fine. :(

[2] As I was verifying this in Perl, I ran into behavior I'd forgotten. I'd thrown in "use strict;" but wasn't getting the errors I expected. Eventually I recalled that $a and $b have special meaning in Perl (I think for comparison functions), and I guess are pre-declared, and I was using $a a la the above code, so strict didn't complain about trying to access $a before assigning to it. Sigh.
mindstalk: (Default)
Months ago, Robbie had found this scoping problem in Python, which I reduced to essentials.

I've started finally learning JavaScript, and it has nicer lambdas than Python, and proper hiding of nested functions unlike Perl. But it has the same scope problem:

g1 = 12;
function func() {
  document.getElementById("demo").innerHTML = g1;

  var g1 = 5;

}
func();


(I'm not including the HTML framework because DW/LJ would yell at me if I did.)

Output is 'undefined', rather than 12. As in Python, the local variable further down shadows the outer scope variable (doesn't matter if the "g1=12" has a 'var' before it) even for lines before the local variable.

As mentioned before, Perl has proper lexical scoping here (though not for nested functions.) I don't think I can even create similar code in Scheme/Lisp, where the scoping is explicit with parentheses. (There's 'define' but I think that makes a new global, and it didn't work.) In Ocaml I have

let g1="10";;

let func () =
  print_endline g1;
  let g1="cat" in
    g1
  ;;

func();;


Which I suspect is as explicit as Lisp parentheses, in its own way; the print line is obviously outside the following "let ... in...".

Profile

mindstalk: (Default)
mindstalk

July 2025

S M T W T F S
  12345
6789101112
13141516171819
20212223242526
272829 3031  

Most Popular Tags

Expand Cut Tags

No cut tags

Syndicate

RSS Atom

Style Credit

Page generated 2025-08-09 13:00
Powered by Dreamwidth Studios