A Javascript journey with only six characters(jazcash.com)
jazcash.com
A Javascript journey with only six characters
http://jazcash.com/a-javascript-journey-with-only-six-characters/
122 comments
For those of you too lazy to open up a Javascript console, it's a function that returns "42".
It also alerts all the primes between 0 and its arg.
Or too lazy to work it out in your head. Jeez.
For those not in the know or too lazy to Google, that's "the answer to life the universe and everything"
Lexical scope with async closures makes it very easy to write async code for example events in a gui or handling multiple clients in a server. Its a big deal.
The title is incorrect; you need "!" and the only reason why I clicked on the article was that doing it without "!" would be a BIG deal. The title of the original article is "A Javascript journey with only six characters" and the topic has been posted/reposted and explained more times than I can count on HN
Oh sorry, how could I miss that :( Fixed it now
I created an account just to thank you for that post, so funny :)
This is an extreme demonstration of the validity of a delightfully snarky blog post by Robert Harper on how dynamic typing is actually static typing using a unitype:
https://existentialtype.wordpress.com/2011/03/19/dynamic-lan...
A string is a Boolean is a number is a function, and braindead conversions can happen without anyone noticing. How does one keep their sanity using a language like that?
https://existentialtype.wordpress.com/2011/03/19/dynamic-lan...
A string is a Boolean is a number is a function, and braindead conversions can happen without anyone noticing. How does one keep their sanity using a language like that?
What the OP takes to the extreme is a property of weak typing, not dynamic typing.
These properties are separate issues. A language is either statically typed or dynamically typed, and it is also either strongly typed or weakly typed.
In a statically typed language, types are attached to variables. In a dynamically typed language, types are attached to values. Do note that many languages don't fit 100% into either category. (Note that the blog post you linked to calls types attached to values classes, but that distinction often isn't made so clearly.)
A weakly typed language performs implicit type conversions as it deems necessary, while a strongly typed language does no implicit type conversions. Most languages don't fit 100% into either category. Usually languages that are considered to be strongly typed still allow you to add integers to floating point numbers, for example.
It is possible for a dynamically typed language to be so strongly typed that it won't do any implicit type conversion, ever. Such a language would not allow you to, say, add an integer and a floating point number without explicitly converting one to the other.
It is also possible for a statically typed language to be so weakly typed that it implicitly converts types everywhere. Such a language might do the exact same things the OP uses, like converting a function to a string of its source code when adding it to a string.
These properties are separate issues. A language is either statically typed or dynamically typed, and it is also either strongly typed or weakly typed.
In a statically typed language, types are attached to variables. In a dynamically typed language, types are attached to values. Do note that many languages don't fit 100% into either category. (Note that the blog post you linked to calls types attached to values classes, but that distinction often isn't made so clearly.)
A weakly typed language performs implicit type conversions as it deems necessary, while a strongly typed language does no implicit type conversions. Most languages don't fit 100% into either category. Usually languages that are considered to be strongly typed still allow you to add integers to floating point numbers, for example.
It is possible for a dynamically typed language to be so strongly typed that it won't do any implicit type conversion, ever. Such a language would not allow you to, say, add an integer and a floating point number without explicitly converting one to the other.
It is also possible for a statically typed language to be so weakly typed that it implicitly converts types everywhere. Such a language might do the exact same things the OP uses, like converting a function to a string of its source code when adding it to a string.
Ah, this was extremely well explained, thank you; I've encountered the strong / static (and weak / dynamic) dichotomy before but I didn't grok the difference until now.
> In a statically typed language, types are attached to variables.
More precisely, expressions may be typed. Of course, free variables are one particular of expression.
> In a dynamically typed language, types are attached to values.
More precisely, tags are attached to objects. An object is a “physical” entity that exists in space (computer memory) and time (from its construction to its destruction or garbage collection). A value is an abstract and atemporal entity that only exists in the language's semantics.
> Such a language would not allow you to, say, add an integer and a floating point number without explicitly converting one to the other.
But it does allow you to add integers and floating points! The result just happens to be an exception, which is a very well defined operation in the semantics of most high-level languages.
If it weren't allowed, it simply wouldn't happen.
More precisely, expressions may be typed. Of course, free variables are one particular of expression.
> In a dynamically typed language, types are attached to values.
More precisely, tags are attached to objects. An object is a “physical” entity that exists in space (computer memory) and time (from its construction to its destruction or garbage collection). A value is an abstract and atemporal entity that only exists in the language's semantics.
> Such a language would not allow you to, say, add an integer and a floating point number without explicitly converting one to the other.
But it does allow you to add integers and floating points! The result just happens to be an exception, which is a very well defined operation in the semantics of most high-level languages.
If it weren't allowed, it simply wouldn't happen.
In a dynamic language, you have to wait until runtime to decide whether an operation is valid or not. Only then can you check an object's tag to see if it proclaims the right type. If it doesn't, non-local exit (of which the exception is the most popular form), is still the best you can do. So, cum grano salis, throwing an exception is a dynamic language's way of disallowing invalid operations.
This isn't true. Throwing an exception is a perfectly valid operation. Of course, it is not the operation you want, but that's a-whole-nother matter.
I didn't say throwing an exception is an invalid operation.
How does your dynamic language tell its user an operation is invalid, based on argument type?
How does your dynamic language tell its user an operation is invalid, based on argument type?
> How does your dynamic language tell its user an operation is invalid, based on argument type?
It doesn't! That's exactly the point. If something is invalid, then it can't happen. At all.
It doesn't! That's exactly the point. If something is invalid, then it can't happen. At all.
If only. What language are you talking about, exactly? This unicorn I have to see.
Any memory-safe language? Say, Python. `[] / []` is a perfectly valid operation: its result is a raised exception misleadingly called `TypeError`. OTOH, in most typed languages, this is a genuinely invalid operation, and it can't happen at all.
Keep it straight in your head, and use strict comparison.
Hey, at least when JS implicitly converts your types, it actually does type conversion, rather than merely casting them, so you often get what you want (looking at you, C).
Hey, at least when JS implicitly converts your types, it actually does type conversion, rather than merely casting them, so you often get what you want (looking at you, C).
As for C, I have to contradict you. Implicit (numeric) type conversions do actual conversions (like char to int, or int to double; even pathological cases like pointer to what-counts-as-Boolean-in-C). The casts you are talking about must be explicit, and thereby are squarely the programmer's responsibility.
Of course, a language that forces all conversions to be explicit is preferable.
Of course, a language that forces all conversions to be explicit is preferable.
I was pretty sure that char to int/int to char in addition was implicit...
Yes, but the char still has to be extended to int. Or the int truncated to char. Except on systems where they happen to be the same size.
EDIT: Supplement: The notion of “type” in C is best translated as “memory layout plan”. Languages of the ML family (including Haskell), e.g., have a notion of “type” closer to mathematical concepts.
EDIT: Supplement: The notion of “type” in C is best translated as “memory layout plan”. Languages of the ML family (including Haskell), e.g., have a notion of “type” closer to mathematical concepts.
With something like flowtype.org.
Good answer. Of course, supplementing static typing after the fact only goes to show that it should have been built into the language to begin with.
Why do I feel like I have read this article a few years ago? I remember it, but it has 2016...
Because this technique was used to bypass EBay's JS blocker a while back.
Interesting, any chance you have a link to a writeup of that?
Because you did. I came to the comments wondering if this was a shameless ripoff of the original or a re-post from the same author.
If it's similar to another article, I'd love to see it. I wrote this over the last two days using only the sources noted at the bottom of the post.
I think the problem is your post reads like it's a discovery of your own, jsfuck and previous artwork are only hinted at the end.
The style makes it easier to see how the approach works, and wouldn't say it implies the OP came up with the technique.
It seems that explanatory articles of this sort often use this style, as it is a great way to get the idea across.
It seems that explanatory articles of this sort often use this style, as it is a great way to get the idea across.
Previous HN context:
https://news.ycombinator.com/item?id=11024511
https://news.ycombinator.com/item?id=11024511
Those links are to generators, not easy-to-read long-form explanations.
Without parenthesis (requires 8 characters though):
http://centime.org/jsfsck/
http://centime.org/jsfsck/
The article does not explain how it gets the {}, which is used to get the Object constructor string. Other than that it's very clear.
It does, see the "fill" step: «So now we have acquired the following extra characters: c,o,v,(,),{,[,],}, .».
Those characters are only inside a string, not as executable code.
You're right. It's possible to use it later on but I've removed it as it doesn't make sense being at that point in the post chronologically. Thanks!
Wow, JavaScript is also an esoteric Language.
I remember similar strange and interesting stuff in Perl, like the spaceship operator.
I remember similar strange and interesting stuff in Perl, like the spaceship operator.
Reminds me a bit of the quest for alphanumeric shell code.
Does anyone know a good sandboxing technology to execute user written javascript in a safe way? (like, on other user machines or on the server)? I have some ideas like "learn programming" that would benefit from this immensely.
Niel Fraser, the guy who created the Blockly block programming toolkit also created a JS Interpreter which allows single stepping of code. https://neil.fraser.name/software/JS-Interpreter/docs.html
I've hacked on this interpreter some, it's pretty nice to read! It implements a very limited subset of JavaScript, something like ES3.
I'd be really interested to hear about other similar implementations of JavaScript in JavaScript. I stopped working on https://github.com/thomasballinger/hotswapping-js-interp#js-... partially because copying the state of the interpreter was relatively slow. I'd be interested in implementations that would handle this better by using a more bytecode-like VM or immutable data structures.
I'd be really interested to hear about other similar implementations of JavaScript in JavaScript. I stopped working on https://github.com/thomasballinger/hotswapping-js-interp#js-... partially because copying the state of the interpreter was relatively slow. I'd be interested in implementations that would handle this better by using a more bytecode-like VM or immutable data structures.
wow! this is really awesome and perfect for my needs. thanks very much :)
https://developers.google.com/caja/
Used it a few years ago. It was a little finnicky to get working right but I was impressed at the time. No idea where the project is at nowadays.
Used it a few years ago. It was a little finnicky to get working right but I was impressed at the time. No idea where the project is at nowadays.
Note that caja doesn't protect against local denial-of-service attacks: user-written javascript executed with it could allocate tons of memory or run forever (`while(true){}`). This may or may not be a problem depending on your use-case. (If you're using caja for code written by mostly-trusted 3rd parties, or for one user's code only on their own machine, then it's not much of an issue. If you're serving code written by one user to another, then it could be a problem.)
Ha, here's an old thread where I asked the caja developers about that exact scenario: https://groups.google.com/forum/#!topic/google-caja-discuss/...
Some possible mitigations but I don't know if they ever implemented them.
Some possible mitigations but I don't know if they ever implemented them.
i saw caja, but it looks really complex, was hoping for something better these days :(
The safest way would be to embed an interpreter written in JS and remove any sort of I/O or FFI capability from the interpreter.
What about Node.js's `vm` module?
Note that the vm module doesn't protect against local denial-of-service attacks: user-written javascript executed with it could allocate tons of memory or run forever (despite any configured timeouts: https://github.com/nodejs/node/issues/3020).
thanks, I didn't actually know about that. it looks like a perfect (and simple) solution for running on nodejs. wish there was something like that for browsers too!
edit: i guess there is this: https://github.com/substack/vm-browserify
edit: i guess there is this: https://github.com/substack/vm-browserify
This is quite timely. I was looking at a library the other day which had IIFEs preceded by '+'. I wondered what the purpose was. Now I know!
I saw a similar video recently called Code Without Keywords which was quite interesting.
https://www.youtube.com/watch?v=LG-ozmTnhdI
https://www.youtube.com/watch?v=LG-ozmTnhdI
[deleted]
I knew about these languages but I've never understood how they were made. This is a fun, fantastic article! These articles make me excited about technology. Even bad ones.
I sighed with relief that the characters were not emoji.
> Javascript is a weird and wondeful language that lets us write some crazy code
Wondeful! A typo six words in.
Wondeful! A typo six words in.
I'm getting a browser security warning on the url on Android.
I don't see the point of a programming language allowing itself braining fucking its users(developer) for serious use
If you don't like JavaScript's type coercion rules, fair enough. But if you're criticizing the fact that you can write JavaScript programs with nothing but punctuation characters, remember that no-one ever does so except as a joke, and that you can do ridiculous stuff in most languages. (Try Googling "obfuscated $YOUR_FAVORITE_LANGUAGE".)
All those idiosyncratic moments were taken into Javascript right from Perl. Perl can do this and much more.
And Perl codebase is huge. Perl is used quite heavily at Amazon, Booking.com and Yahoo, among others.
Say what you want about Perl, but it is fun and hacker-friendly. I enjoyed it for many years.
And Perl codebase is huge. Perl is used quite heavily at Amazon, Booking.com and Yahoo, among others.
Say what you want about Perl, but it is fun and hacker-friendly. I enjoyed it for many years.
It's optimizing for writeability rather than readability.
[deleted]
thanatropism(9)
One more reason for the world to hate JavaScript ? :(
[deleted]
this is insane. someone should create a js obfuscator that converts human readable code to this.
It is linked at the end of the article:
http://www.jsfuck.com/
http://www.jsfuck.com/
some how the link to
http://aem1k.com/aurebesh.js/
is missing, where he takes this one step further.
Oh dear...
this would obviously be a fun thing to do, but I wonder how much larger the code will get via this means of obfuscating.
Maybe space isn't a concern in your use case though...
Maybe space isn't a concern in your use case though...
I imagine it could be largely mitigated by compression
I have a "compression" feature for my jsfuck fork: http://centime.org/jsfsck/
only worth it for long enough code, but then the browser is having a lot of trouble parsing the obfuscated version...
Still: "The js code of this page has been encoded (see source). Compression reduced it from 288k to 37k characters."
only worth it for long enough code, but then the browser is having a lot of trouble parsing the obfuscated version...
Still: "The js code of this page has been encoded (see source). Compression reduced it from 288k to 37k characters."
With some code you don't need to run it though an obfuscator for it to be obfuscated
So glad I don't write in a "weird and wondeful language that lets us write some crazy code that's still valid"
This doesn't make me want to use JS. The power of JS is in two things, it's in every major browser and it doesn't completely suck. JS syntax kind of sucks. The power in JS is that it's dynamic and lets you send functions around, but defining functions is much uglier than defining a lambda in Ruby:
-> {anything goes here}
or
->(a,b,c) {anything goes here}
The problem with Ruby is that you then have to .() the lambda vs. (), so that is more verbose than just calling the function.
If browsers were to embrace a language that was more Ruby-like and less clunky than JS, I'm sure I'd use it more.
-> {anything goes here}
or
->(a,b,c) {anything goes here}
The problem with Ruby is that you then have to .() the lambda vs. (), so that is more verbose than just calling the function.
If browsers were to embrace a language that was more Ruby-like and less clunky than JS, I'm sure I'd use it more.
Ruby suffers from a confusing set of overlapping features in Procs, Blocks and Lambdas. JavaScript's function passing is a lot less opaque.
ES6 lets you define functions like a => a * 2
Or (a, b, c) => a * b ^ c
Or (a, b, c) => a * b ^ c
That's succinct, but less clear than the Ruby version, imo, as you don't have any scope indicators required for the function body.
JS:
JS:
let f = (a,b,c) => a * b ^ c;
f(2,3,4);
vs. Ruby: f = ->(a,b,c) { a * b ^ c }
f.(2,3,4)
Ruby's shorter and clearer. But, when you use the Ruby lambda more than once in the code, you lose the brevity advantage, because of the "extra" dot. But, in Ruby I use methods more than lambdas, which would be: def f(a,b,c) { a * b ^ c }
f(2,3,4)> Ruby's shorter and clearer.
I would say the different is negligible here and claiming one is more clear than the other is purely preferential. Coming from a JS background the JS is more clear but not substantially enough for me to claim it is outright more clear a language syntax. Someone coming from a ruby background may argue the other direction.
Some languages are quite different but you are splitting hairs here and trying to be conclusive about it.
I would say the different is negligible here and claiming one is more clear than the other is purely preferential. Coming from a JS background the JS is more clear but not substantially enough for me to claim it is outright more clear a language syntax. Someone coming from a ruby background may argue the other direction.
Some languages are quite different but you are splitting hairs here and trying to be conclusive about it.
None is preventing you from writing
let f = (a,b,c) => {a * b ^ c};
in JS
the ruby versions isnt shorter though; you just included things you dont need: semi colons and 'let'
But it's not without its warts, and this is one of the worst. Although it's sometimes fun to mess with, nonetheless.
To see this taken to one of its logical extremes, check out If Hemmingway Wrote Javascript's entry for Douglas Adams: