简体   繁体   English

将JavaScript对象转换为ClojureScript:Getter和Setter属性

[英]Convert JavaScript Object to ClojureScript: Getter and Setter Properites

I'm struggling with the following issue: 我正在努力解决以下问题:

Usually JS objects are converted via js->clj to ClojureScript. 通常,JS对象通过js-> clj转换为ClojureScript。 This works for objects of the prototype Object. 这适用于原型对象的对象。 For the other's I'm using: 对于其他的我正在使用:

(defn jsx->clj [o]
  (reduce (fn [m v] (assoc m (keyword v) (aget o v)))  {} (.keys js/Object o)))

I discovered, that "properties", which are getter functions behind the scenes cannot be transformed by these operations. 我发现,这些“属性”是幕后的吸气功能,无法通过这些操作进行转换。

Does anybody have any experiences with this? 有人对此有任何经验吗?

I'm not sure what you mean when you say "getter functions behind the scenes cannot be transformed by these operations". 我不确定当您说“幕后的getter函数无法通过这些操作转换”时的意思。

One of the issues is that when you convert JS object into CLJS map like that, getters and setters will not be bound to the original JS object, thus they will not have access to the properties of this object. 问题之一是,当您将JS对象这样转换为CLJS映射时,getter和setter不会绑定到原始JS对象,因此它们将无法访问此对象的属性。

Consider the following code: 考虑以下代码:

;; This is your function, no changes here.
(defn jsx->clj [o]
  (reduce (fn [m v] (assoc m (keyword v) (aget o v)))  {} (.keys js/Object o)))


;; This is an improved version that would handle JS functions that
;; are properties of 'o' in a specific way - by binding them to the
;; 'o' before assoc'ing to the result map.
(defn jsx->clj2 [o]
  (reduce (fn [m v]
            (let [val (aget o v)]
              (if (= "function" (goog/typeOf val))
                (assoc m (keyword v) (.bind val o))
                (assoc m (keyword v) val))))
          {} (.keys js/Object o)))

;; We create two JS objects, identical but distinct. Then we convert
;; both to CLJS, once using your function, and once using the improved
;; one.
;; Then we print results of accessing getter using different methods.
(let [construct-js (fn [] (js* "new (function() { var privProp = 5; this.pubProp = 9; this.getter = function(x) { return privProp + this.pubProp + x; }; })"))
      js-1 (construct-js)
      js-2 (construct-js)
      clj-1 (jsx->clj js-1)
      clj-2 (jsx->clj2 js-2)]
  (.log js/console "CLJS objects: " (.getter js-1 10) ((:getter clj-1) 10) (.getter js-2 10) ((:getter clj-2) 10)))

This prints: 打印:

CLJS objects:  24 NaN 24 24

This means that the following code: ((:getter clj-1) 10) failed, while ((:getter clj-2) 10) worked as expected. 这意味着以下代码: ((:getter clj-1) 10)失败,而((:getter clj-2) 10)工作。 The second one worked, because the .bind() has been used to tie function with the JS object properly. 第二个有效,因为.bind()已用于将函数与JS对象正确绑定。

This issue, if that's indeed what has failed for you, is the equivalent of the following mistake sometimes done in JS: 如果确实为您带来了问题,那么此问题等同于有时在JS中执行的以下错误:

var Constructor = function() {
  var privProp = 5;
  this.pubProp = 9;
  this.getter = function(x) {
    return privProp + this.pubProp + x;
  };
}
var obj1 = new Constructor();
var obj2 = new Constructor();
var fn1 = obj1.getter;             // Invalid, fn1 will not be bound to obj1.
var fn2 = obj2.getter.bind(obj2);  // Note .bind here.
console.log(fn1(10), fn2(10));

That prints similar output: 打印类似的输出:

NaN 24

Again, fn1 that has not been bound to obj1 returned invalid output. 同样,尚未绑定到obj1 fn1返回无效输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM