3ixfra
Last Updated: February 25, 2016
·
1.807K
· alexisraca

Coffeescript Private functions scoping, accessing constructor variables and Inheritance

The other day I came across a task on refactoring some common coffeescript into class - object oriented, I'm not very pro and learned a lot through research of 2-3 days leading to a mayor conclussion about scoping: IT IS A MESS for noobs like me.

Any way, I solved some problems where inheriting was essential

First we create our view class

class FolderView
  constructor: (@id , @nme) ->

Then we need to add it some JST for template rendering and create our inner html object

class FolderView
  constructor: (@id, @nme) ->
     @template: "path/to/jst"        
     @folder_view = folder_html(@id, @nme, @template)


  folder_html = (id, name, path ) ->
    $(JST[path](id: id, name: name))    #this will return the html necesary to use our folder in the view
  insert: ->
    $("table").append(@folder_view)


folder = new FolderView 1, "myfolder"
folder.insert()

This will insert our new folder generating it via JST into the content of the page, but theres something wrong here... what if we want to inherit its methods/properties?

we cant do:

folder_html = (id, name, path)->
  super

because it is a function only present inside the scope of the main class, then what if we wanted to play the template path as a global property? al that leading to this:

class FolderView
  constructor: (@id, @nme) ->
    @folder_view = FolderView.folder_html(@id, @nme)

  template_path: "path/to/jst"

  @folder_html: (id, name)->
    @template()(id: id, name: name)

  @template: ->
    JST[@prototype.template_path]

  insert: ->
    $("table").append(@folder_view)


folder = new FolderView 1, "myfolder"
folder.insert()

As you can see we added @ to some of the functions, this makes refference to "this" as we know for common coffeescript, but what does that mean?, it means they become "private" or part of the prototypal class FolderView scoping them, thats why we call the method outside the scope of @template and @folder_html as:

FolderView.folder_html(@id, @name)

now.. why do this?, cant we just leave them as common functions? as we know they would become a common:

folder_html = function(){ ....code.... }

but then we could not play inheritance and would become repetitive code, and as we know, thats not very classy feels like a sir

so under inheritance we want to create a form view to create our folders at the view, so will make this:

class NewFolderView extends FolderView
  constructor: (@parent_folder_id) ->
    @folder_view =  FolderView.folder_html(@parent_folder_id)

  template_path: "path/to/new_jst"

  @folder_html: (parent_id) ->
    @template()(parent: parent_id) #heres the point

So here's our point of the article, as we know inheritance means all our parents can do, we can!!
this means when we extend the FolderView class all its properties are inherited to the children:

@template: ->

allows us to call it as prototypal method in the class, inheriting it to any class it is extent to!! and:

@template: ->
  JST[@prototype.template_path]

allows us to call the new template_path declared under NewFolderView because we want a "new" template with a form, not the resulting named and with id using @prototype."property"

this may have some issues or may be easyer acomplished but the main concern was the fact that scoping needs to be understood realy well before adventuring into more complex stuff in coffeescript, mostly with low knowledge in pure javascript like myself

2 Responses
Add your response

15001

Interesting read up, but it looks like a messy job to achieve what you wanted.

Why don't you declare the template_path in the constructor for instance? Can't you just extend the constructor via super()? I wouldn't start messing with @prototype for vars. Those should be in the constructor in my opinion.

Doesn't it work to just move the template path to the constructor and declare it via @templatepath instead of prototype?
Then call super() in the extended one and the @template should have access to @template
path and you can access that from outside as well.

I haven't tried this but it feels like that should work and it should achieve what you're trying to do via prototype. Let me know, i might be missing a reason for putting it there..

You could also always achieve something similar with a object mixin, which might actually be nicer than enforcing classical object oriented patterns. I mean the classes from coffeescript basically do copying of the object anyway..

Let me know!

over 1 year ago ·
15010

thank you for your reply, about the superi-ing in the "constructor" we prevent using super in it because the extending class NewFolderView reference a "new" view, which means it has no Id or Name yet, it is a form with a "parentfolderid" only, we wanted it for a file-tree system so it became a need to have many extending classes for a folder like, EditFolderView, NewFolderView, etc...

about the @prototype... well, i have not found any problems on using it but yes @template_path would be accessed using it as a normal global variable and not prototypal like this:

template_path = "path/to/template" 

this way we may not need to call it as:

@prototype.template_path

as you say calling it with @prototype may have some issues but i have not found any yet, it may enlighten me if you could give me some info about problems using it.


EDIT

Correcting myself:

after trying the change in my answer 2 problems may colide:

if we add it as a global variable:

template_path = "path/to/template"

under the inherited @template method it would become unable to use the "newfoldertemplate" variable

TAKING A LOOK AT RENDERED JAVASCRIPT

@template: ->

is using refference to the class it is declared into (FolderView), when we see it in javascript it is:

FolderView.template = function() {
    return JST[this.prototype.template_path];
};

and the template path prototypal variables are:

NewFolderView.prototype.template_path = "path/to/new_folder_view";
FolderView.prototype.template_path = "path/to/folder_view

Now looking at the inherited javascript it has no @template function/method because the inheriting class relies in EXTENDING/INHERITING only.

then when we call:

NewFolderView.folder_html(parent_id)

the NewFolderView makes the function work in it's own scope, calling its own version of the template_ path under @template via the @prototype.template_ path

over 1 year ago ·