Update - July 4, 2017

The original post is now outdated. Instead use goog.object/get, goog.object/getValueByKeys, and goog.object/set.

Example from the cljs api:

;;instead of aget
(require 'goog.object)
(def obj #js {:foo #js {:bar 2}})

(goog.object/get obj "foo")
;;=> #js {:bar 2} 

(goog.object/getValueByKeys obj "foo" "bar")
;;=> 2

;;instead of aset
(def obj #js {:foo 1})

(goog.object/set obj "foo" "bar")
obj
;;=> #js {:foo "bar"}
 

See CLJS-2148 and CLJS-2149 for more details.






The rest of this post is now outdated

Konrad Garus has a good post explaining the details of accessing js properties from cljs. It’s worth your time to read the entire post, but here are some general guidelines.

Use .-property for cljs

(.-property obj) ;;get property
(set! (.-property obj) v) ;;set property
 

In the normal case, you’ll want to use .-property to access js properties. In the line-reader example, we use .-_lastLineData to get/set data on this.

(defn- transform [chunk encoding done]
  (this-as this
    (let [data (if (.-_lastLineData this) ;;get the property
                 (str (.-_lastLineData this) chunk)
                 (str chunk))
          lines (clojure.string/split data (js/RegExp. eol "g"))]
      (set! (.-_lastLineData this) (last lines)) ;;set the property
      (doseq [line (butlast lines)]
        (.push this line))
      (done))))

Using .-property allows the compiler to rename the property during advanced compilation, e.g. _lastLineData could be renamed a. (.-property object) is the idiomatic way to access js properties.

Use (aget object "property") for js

(aget obj "property") ;;get property
(aset obj "property" v) ;;set property
 

If you want your code to be accessible in js, use aget/aset with strings referring to the property.

(aset user "name" "boston")

;;js, works as `name` won't be renamed by the compiler
;;user.name == "boston"; ;;=> true

(set! (.-name new-user) "boston 2.0")

;;js, doesn't work as `name` could be renamed by the compiler
;;new-user.name == "boston 2.0"; ;;=> false
 

Don’t mix accessors

If you sometimes use (.-property object) and other times use (aget object "property"), you’ll run into confusing bugs when it comes time to ship. There are few things as frustrating as bugs that only show up in prod (where you’re using advanced compilation). Be consistent, and you’ll save yourself unnecessary headaches.

Find this post useful? Share the love!

Recent Posts