Error formatting macro: pagetree: java.lang.NullPointerException
Skip to end of metadata
Go to start of metadata
You are viewing an old version of this page. View the current version. Compare with Current  |   View Page History

Problem

In any programming language with both first class functions and objects, the handling of a this 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 this independent to its JavaScript interop. Currently, there is no good way to refer to a JavaScript this aside from the (js* "this") hack. ClojureScript should more effectively handle this in a way that is safe and intuitive.

A bit about this in general

ClojureScript functions are compiled to JavaScript functions and are therefore subject to the implicit this behavior.

Given a function f defined as:

    function f(a,b) { 
      print([this,a,b]) 
    }

Calling f directly yields:

    f(1,2)
    // [object global],1,2

note: in JavaScript strict mode this would be bound to undefined in the previous example

In this case, the this variable is implicitly bound to the global object.

However, when bound as a property on an object, f's implicit this changes:

    var o = {}
    o.m = f
    o.m(1,2)
    // [object Object],1,2

Now the value of this is the instance o.

ClojureScript and this

The problem in ClojureScript can be illustrated in the following:

    (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]

That is, the value for this in the body of f is bound to the global object and not the instance o.

A possible solution

One possible solution to this dilemma is to use GClosure's bind function:

    (set! cljs.user.o.m (goog.bind f o))
    ((.m o) 1 2)
    ;; [#<[object Object]> 1 2]

This will also work for multi-arity functions.

A possible syntax

    (extend-object o
      {:m f})

Would expand into a number of calls to goog.bind on the object o and then return o itself. The use of the (js* "this") could possibly be replaced with the js namespaced reference js/this.

Labels: