diff --git a/src/cljs/cljs/core.cljs b/src/cljs/cljs/core.cljs
index 4f7bd94..b9be1ac 100644
--- a/src/cljs/cljs/core.cljs
+++ b/src/cljs/cljs/core.cljs
@@ -769,6 +769,13 @@ reduces them without incurring seq initialization"
   ([keyfn comp coll]
      (sort (fn [x y] ((fn->comparator comp) (keyfn x) (keyfn y))) coll)))
 
+(defn shuffle
+  "Return a random permutation of coll"
+  [coll]
+  (let [a (to-array coll)]
+    (garray/shuffle a)
+    (seq a)))
+
 (defn reduce
   "f should be a function of 2 arguments. If val is not supplied,
   returns the result of applying f to the first 2 items in coll, then
diff --git a/test/cljs/cljs/core_test.cljs b/test/cljs/cljs/core_test.cljs
index 4fda2da..5324d57 100644
--- a/test/cljs/cljs/core_test.cljs
+++ b/test/cljs/cljs/core_test.cljs
@@ -590,6 +590,13 @@
   (assert (= ["a" [ 1 2] "foo"] (sort-by count ["foo" "a" [1 2]])))
   (assert (= ["foo" [1 2] "a"] (sort-by count > ["foo" "a" [1 2]])))
 
+  ;; shuffle
+  (let [coll [1 2 3 4 5 6 7 8 9 10]
+        ; while it is technically possible for this test to fail with a false negative,
+        ; it's _extraordinarily_ unlikely.
+        shuffles (filter #(not= coll %) (take 100 (iterate shuffle coll)))]
+    (assert (not (empty? shuffles))))
+
   ;; js->clj
   (assert (= {"a" 1, "b" 2} (js->clj (js* "{\"a\":1,\"b\":2}"))))
   (assert (= {:a 1, :b 2} (js->clj (js* "{\"a\":1,\"b\":2}") :keywordize-keys true)))
