13

I am using a JavaScript library that exposes a constructor as a property of a global object.

In JavaScript, I can call the constructor like this.

var thing = new Library.Thing();

How do I call the constructor in ClojureScript? None of these work.

; These all cause compiler errors
(new (.-Thing js/Library)) ; First arg to new must be a symbol
(new (.Thing js/Library))
(new .-Thing js/Library)
(new .Thing js/Library)
(new js/Library/Thing)     ; Invalid token: js/Library/Thing

; These all compile to different JS than I am looking for
((.-Thing js/Library).) ; Library.Thing.call(null, _SLASH_);
((.Thing js/Library).)  ; Library.Thing().call(null, _SLASH_);

It works fine if I use js* but that's cheating, right?

(js* "new Library.Thing()")

What is the proper way to call a constructor function that is a property of another object?

1 Answer 1

11

If you look at http://himera.herokuapp.com/synonym.html you can find the specific syntax to instantiate objets in clojurescript.

I wrote this js mock library based in this documentation to make a test:

function Person(name) {
this.name = name;
}

Person.prototype.greet = function() {
return "Hello, " + this.name;
};


var f={
"hola":"hola juan",

Person:Person

};

var person=new f.Person("Juan");
alert(person.greet());

Then from clojurescript you have to use the dot syntax (but prefixing with "js/" your js global type):

(let [Person (.-Person js/f)
        juan (Person. "Juan")
        ]
    (.log js/console  (.greet juan)))

I don't mention in this answer the :externs property of your cljsbuild compilation beacuse I understand that you are including your js script library directly in your html head document. So, if this line works for you (js* "new Library.Thing()") it'll mean that the js library is available from the cljs-js-compiled.
Anyway, I left an "alert" in the js mock library to check that the file is correctly loaded

I hope it works for you
Juan

Sign up to request clarification or add additional context in comments.

2 Comments

So in other words, if I bind the constructor to a local first, I can call it. (let [Thing (.-Thing js/Library)] (new Thing)) works fine, as does (let [Thing (.-Thing js/Library)] (Thing.)).You are correct about the script being included directly in the document.
Hi Josh, you are right about the local constructor binding. It's a very curious behavior the dot js constructor ".". Just realizing that you can invoke normal functions with this "." (defn -log [message] (.log js/console message) ) (-log. "Hello Josh")

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.