Blogged by Ujihisa. Standard methods of programming and thoughts including Clojure, Vim, LLVM, Haskell, Ruby and Mathematics written by a Japanese programmer. github/ujihisa

Monday, January 7, 2013

Day 4 -- JavaScript in a week

previous post <-> next post

I accidentally started playing SimCity3000 and it ate big amount of my time..


return is the only one feature to cancel executing the rest of statements, since there's no try/catch exception handling in this subset. Since the run- function to sequentially execute statements isn't something like a loop but an explicit recursion, to implement return, just simply don't recur.

(run '[(var f (function []
                        [(fcall 'console.log [1])
                         (return 9)
                         (fcall 'console.log [2])]))
       (fcall 'console.log [(fcall 'f [])])])

This outputs 1 and 9 but not 2.


JavaScript has a unary operator typeof to tell the type of a value/variable-name.

> typeof 1
> var x = 1
> typeof x
> typeof y

Since typeof isn't a function it has more power than functions; it also accepts undefined variables without throwing ReferenceError.

(run '[(fcall 'console.log [(typeof 1)]);=> "number"
       (var x 1)
       (fcall 'console.log [(typeof x)]);=> "number"
       (fcall 'console.log [(typeof y)]);=> "undefined"
       (fcall 'console.log [(typeof (fcall '+ ['x 2]))])]);=> "number"


== is one of the most difficult aspect of JavaScript. The behavior is too tricky to understand.

> 1 == ['1']
> [] == []
> [] == ''
> 1 == true
> 1 == 'true'
> '1' == true

According to specification, the definition of == is

If the two operands are not of the same type, JavaScript converts the operands then applies strict comparison. If either operand is a number or a boolean, the operands are converted to numbers if possible; else if either operand is a string, the other operand is converted to a string if possible. If both operands are objects, then JavaScript compares internal references which are equal when operands refer to the same object in memory.

Well, I couldn't clearly understand it. What if one operand is a number and the other is a boolean? What is an operand is a number but the other operand isn't possible to be converted? They aren't written.

I gave up and made one that works fine for now..

(run '[(fcall 'console.log [(fcall '== [1 1])]);=> true
       (fcall 'console.log [(fcall '== [1 2])]);=> false
       (fcall 'console.log [(fcall '== ["1" 1])]);=> true
       (fcall 'console.log [(fcall '== ["1" 2])]);=> false
       (fcall 'console.log [(fcall '== ["1" "1"])]);=> true
       (fcall 'console.log [(fcall '== ["1" "2"])]);=> false
       (fcall 'console.log [(fcall '== ["aaa" "aab"])])]);=> false


[] is a unary operator for objects. Note that "object" is a hash-map or an array in JavaScript terminology. I named it as aref borrowed from Ruby's parser which means array ref, since Clojure doesn't recognize '[] as Symbol but as vector. To distinguish it with user-defined something which name is aref, I named it as -aref.

(run '[(fcall 'console.log [(fcall '-aref [{"0" "a" "1" "b" "2" "c"} 0])])]);=> "a"
(run '[(fcall 'console.log [(fcall '-aref [{"0" "a" "1" "b" "2" "c"} "1"])])]);=> "b"
(run '[(fcall 'console.log [(fcall '-aref [{"0" "a" "1" "b" "2" "c"} 3])])]);=> "undefined"
(run '[(fcall 'console.log [(fcall '-aref [{"0" "a" "1" "b" "2" "c"} "4"])])]); => "undefined"

No comments:

Post a Comment