What am I doing wrong here? I'm using the fat arrows => for my callbacks, however when the code reaches cb.onEndElement and calls @returner I get an null object exception. So why doesn't @returner exist?
class Parser
constructor: () ->
@returner = (data) ->
searchParser: new xml.SaxParser (cb) =>
cb.onStartElementNS (elem, attrs, prefix, url, ns) =>
if elem is "results" then @results = []
else if elem is "title" then @curr = "title"
else @curr = "none"
cb.onCdata (cdata) =>
if @curr is "title" then @book.title = cdata
cb.onEndElementNS (elem, prefix, url) =>
@results.push @book if elem is "book"
cb.onEndDocument =>
@returner @results
search: (str, callback) ->
@returner = callback
@searchParser.parseString str
p = new Parser
p.search "somexml", (data) ->
console.log JSON.stringify data
With the rise of ES6/7 and TypeScript, it seemed like CoffeeScript would become obsolete. But it's not. CoffeeScript was one of the pioneers of the compile-to-JavaScript concept. In fact, some of things you now see in the modern JavaScript appeared in the first version of CoffeeScript some 8 years ago.
CoffeeScript is something that makes even good JavaScript code better. CoffeeScript compiled code can do everything that natively written JavaScript code can, only the code produced by using CoffeeScript is way shorter, and much easier to read.
CoffeeScript is a programming language that compiles to JavaScript. It adds syntactic sugar inspired by Ruby, Python, and Haskell in an effort to enhance JavaScript's brevity and readability. Specific additional features include list comprehension and destructuring assignment.
Load a remote script from the current domain via XHR. Activate CoffeeScript in the browser by having it compile and evaluate all script tags with a content-type of text/coffeescript . This happens on page load. Listen for window load, both in decent browsers and in IE.
Your method search
needs a fat-arrow =>
in order to bind it to instances of Parser
.
Additionally, although the line searchParser: new xml.SaxParser (cb) =>
compiles, it's probably not doing what you want, because the fat arrow is binding the callback to Parser
and not this
. You have two options:
@searchParser = new xml.SaxParser (cb) => ...
in your constructor instead, given the way you are calling it. searchParser: () => new xml.SaxParser (cb) =>
and call it with parens lower down: @searchParser().parseString str
, which would create a searchParser
method bound to this
As an example, here are my two solutions, as well as your original line, slightly simplified, as well as the compiled code, for compare and contrast purposes:
Simplified example in CoffeeScript:
class Parser
constructor: () -> @searchParser1 = new xml.SaxParser (x) => console.log(x)
searchParser2: () => new xml.SaxParser (x) => console.log(x)
searchParser: new xml.SaxParser (x) => console.log(x)
Compiled JavaScript:
var Parser;
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
Parser = (function() {
function Parser() {
this.searchParser2 = __bind(this.searchParser2, this);
this.searchParser1 = new xml.SaxParser(__bind(function(x) {
return console.log(x);
}, this));
}
Parser.prototype.searchParser2 = function() {
return new xml.SaxParser(__bind(function(x) {
return console.log(x);
}, this));
};
Parser.prototype.searchParser = new xml.SaxParser(__bind(function(x) {
return console.log(x);
}, Parser));
return Parser;
}).call(this);
Note how searchParser1
and searchParser2
have their callbacks bound to this
and searchParser
's is bound to Parser
.
As always, the "Try CoffeeScript" button at the CoffeeScript homepage (http://jashkenas.github.com/coffee-script/) is your friend!
First off, the concept you're talking about isn't "scope"—it's this
, also informally called the "context." And it's certainly one of the trickiest concepts in JavaScript (and thus CoffeeScript), even though the rules are fairly simple. Perhaps it's because the word this
itself, which doesn't seem like its meaning should be so easily changed depending on how a function is called...
Nicholas' answer is dead-on, but I recommend that you also read up on this
and try to really understand it, rather than just using =>
all the time (it's a great tool, but not always the right one). A few resources I recommend:
this
this
?
this
, as well as scope, in a fair amount of depth)If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With