Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Sign Up
Dashboard
Clojure Design
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
Colour
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Undo
Redo
Keyboard Shortcuts Help
<h1>Problem 1: ClojureScript functions as object methods</h1> <p>In any programming language with both first class functions and objects, the handling of a <code>this</code> parameter is a cause for complication. In the case of JavaScript the picture is particularly sticky due to langauge foibles. An additional complication, ClojureScript does not have its own notion of <code>this</code> independent to its JavaScript interop. Currently, there is no good way to refer to a JavaScript <code>this</code> aside from the <code>(js* "this")</code> hack. ClojureScript should more effectively handle <code>this</code> in a way that is safe and intuitive.</p> <h3>A bit about <code>this</code> in general</h3> <p>ClojureScript functions are compiled to JavaScript functions and are therefore subject to the implicit <code>this</code> behavior.</p> <p>Given a function <code>f</code> defined as:</p> <table class="wysiwyg-macro" data-macro-name="noformat" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e25vZm9ybWF0fQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> function f(a,b) { print([this,a,b]) } </pre></td></tr></table> <p>Calling <code>f</code> directly yields:</p> <table class="wysiwyg-macro" data-macro-name="noformat" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e25vZm9ybWF0fQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> f(1,2) // [object global],1,2 </pre></td></tr></table> <p><em>note: in JavaScript strict mode</em> <code><em>this</em></code> <em>would be bound to</em> <code><em>undefined</em></code> <em>in the previous example</em></p> <p>In this case, the <code>this</code> variable is implicitly bound to the global object.</p> <p>However, when bound as a property on an object, <code>f</code>'s implicit <code>this</code> changes:</p> <table class="wysiwyg-macro" data-macro-name="noformat" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e25vZm9ybWF0fQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> var o = {} o.m = f o.m(1,2) // [object Object],1,2 </pre></td></tr></table> <p>Now the value of <code>this</code> is the instance <code>o</code>.</p> <h3>ClojureScript and <code>this</code></h3> <p>The problem in ClojureScript can be illustrated in the following:</p> <table class="wysiwyg-macro" data-macro-name="noformat" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e25vZm9ybWF0fQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> (defn f [a b] (println [(js* "this") a b])) ;;roughly equivalent to the f function above (def o (js* "{}")) (set! cljs.user.o.m f) ((.m o) 1 2) ;; [#<[object Global]> 1 2] </pre></td></tr></table> <p>That is, the value for <code>this</code> in the body of <code>f</code> is bound to the global object and not the instance <code>o</code>.</p> <h2>A possible solution for ClojureScript functions as methods</h2> <p>One possible solution to this dilemma is to use GClosure's <code>bind</code> function:</p> <table class="wysiwyg-macro" data-macro-name="noformat" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e25vZm9ybWF0fQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> (set! cljs.user.o.m (goog.bind f o)) ((.m o) 1 2) ;; [#<[object Object]> 1 2] </pre></td></tr></table> <p>This will also work for multi-arity functions.</p> <h3>A possible syntax</h3> <table class="wysiwyg-macro" data-macro-name="noformat" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e25vZm9ybWF0fQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> (extend-object o {:m f}) </pre></td></tr></table> <p>Would expand into a number of calls to <code>goog.bind</code> on the object <code>o</code> and then return <code>o</code> itself. The use of the <code>(js* "this")</code> could possibly be replaced with the <code>js</code> namespaced reference <code>js/this</code>.</p> <h3>Caveat (or bug, depending on how you look at it)</h3> <p>Any function attached to an object via <code>extend-object</code> will forever thereafter refer to said object as its <code>this</code>.</p> <h1>Problem 2: ClojureScript functions and co-opted <code>this</code></h1> <p>Some JavaScript libraries use <code>this</code> as a dynamic variable bound to some special value within special contexts. For example, JQuery uses this approach:</p> <table class="wysiwyg-macro" data-macro-name="noformat" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e25vZm9ybWF0fQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> $('li').each(function(index) { alert(index + ': ' + $(this).text()); }); </pre></td></tr></table> <p>In this example, <code>this</code> would be bound to each element in turn retrieved by the selector <code>$('li')</code> and processed in the <code>each</code> loop. techniques of this sort pull this off by explicitly passing a value for the implicit <code>this</code> to the target function as an argument to the <code>call</code> method. In other words, something (in spirit) like:</p> <table class="wysiwyg-macro" data-macro-name="noformat" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e25vZm9ybWF0fQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> (defn f [] (.x js/this)) (f) ;=> undefined (.call f (js* "{x : 9}")) ;=> 9 </pre></td></tr></table> <p>This is effectively what <code>goog.bind</code> does, so this type of behavior should <strong>just work</strong> using ClojureScript functions.</p>
Attachments
Labels
Location
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced