January 3, 2020
By: anna
goog.object/getValueByKeys和aget更简便的取出#js的值
在clojure中我们经常会取到js类型的返回值,根据以往的经验,我们一般会选择用js->clj进行转换,然后get-in我们想要的值。我以为这个方法是万能的,但事实上并不是,下面让我们看看哪几种情况可以使用转化方法:
class myObject {
constructor(name) {
this.name = name;
}
}
window.myObj = new myObject("hello");
window.myMap = {"key": "value"};
window.myArray = ["Saab", "Volvo", "BMW"];
js map可以用js->clj进行转换
js/window.myMap
(js->clj js/window.myMap :keywordize-keys true)
js Array可以用js->clj进行转化
js/window.myArray
(js->clj js/window.myArray :keywordize-keys true)
这些都是很常见的,但是还有些类型转化方法并不支持:
js object, NO!!!! js->clj不好用了
js/window.myObj
(js->clj js/window.myObj :keywordize-keys true)
最近就是遇到了这个难题。我想写一个滑动删除的功能,用到了on-touch-start事件,我需要获取的是里面的clientX。如果是用javascript的话,我们这么取值
event.touches[0].clientX
但是在clojure中,我们只能获取到这一步:
(js->clj (.-touches e) :keywordize-keys true)
通常我们想进一步获取里面的clientX,会这样写:
(get-in (js->clj (.-touches e) :keywordize-keys true) [0 :clientX])
但是失败了,返回的null,尝试了很过方法,都取不到值,最后求助了大神,进而发现有一种方法可以更快个安全的取到我们想要的结果。
aget或者goog.object/getValueByKeys可以从object中拿到值
(aget js/window.myObj "name")
(goog.object/getValueByKeys js/window.myObj
#js ["name"])
那么我们再来看一下用这两种方法怎么从on-touch-start中取出clientX:
aget取值:
(-> e
(.. -touches)
(aget 0)
(.. -clientX))
goog.object/getValueByKeys取值:
(goog.object/getValueByKeys e
#js ["touches" 0 "clientX"])
我再把两种语法详细补充一下:
aget的语法
定义一个obj
{foo: {entries: [{prop: "alpha"},
{prop: "beta"}]}}
(aget obj "foo" "entries" 1 "prop")
getValueByKeys的语法
(:require [goog.object :as gobj])
先来看语法
(goog.object/getValueByKeys obj
#js ["foo" "entries" 1 "prop"])
google.object/getValueByKeys是作为get-in的JavaScript模拟。
我们在进行js->clj这种转化的时候是需要时间的,阻塞我们代码的运行。
不过呢,goog.object要快个几百倍
注意下面的性能测试, 分别执行100万次.
(simple-benchmark [obj #js {:foo #js {:entries #js [#js {:prop "alpha"} #js {:prop "beta"}]}}]
(goog.object/getValueByKeys obj
#js ["foo" "entries" 1 "prop"]) 1000000)
(simple-benchmark [obj #js {:foo #js {:entries #js [#js {:prop "alpha"} #js {:prop "beta"}]}}]
(let [m (js->clj obj :keywordize-keys true)]
(get-in m [:foo :entries 1 :prop])) 1000000)
看起来,把js数据转成clojure的结构非常不合算呀. 如非必须, 尽量使用goog.object来做吧