2011-05-18 15 views
5

¿Qué estoy haciendo mal aquí? Estoy usando las flechas gordas => para mis devoluciones de llamada, sin embargo, cuando el código llega a cb.onEndElement y llama a @returner obtengo una excepción de objeto nulo. Entonces, ¿por qué no existe @returner?Problema de alcance de CoffeeScript

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 
+0

¿Mi respuesta solucionó tu problema? – nicolaskruchten

+0

Sí, gracias. – Matthew

Respuesta

5

Su método search necesita una grasa flecha => a fin de obligar a las instancias de Parser.

Además, aunque la línea searchParser: new xml.SaxParser (cb) => compila, es probable que no hacer lo que quiere, porque la flecha de grasa es vinculante para la devolución de llamada a Parser y no this. Tiene dos opciones:

  1. probablemente debería poner @searchParser = new xml.SaxParser (cb) => ... en su constructor lugar, dada la forma en la que está llamando él.
  2. de lo contrario podría utilizar searchParser:() => new xml.SaxParser (cb) => y llamarlo con parens más abajo: @searchParser().parseString str, lo que crearía un método searchParser obligado a this

A modo de ejemplo, aquí están mis dos soluciones, así como su línea original, ligeramente simplificada, así como el código compilado, para comparar y contrastar los propósitos: ejemplo

simplificado en 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) 

JavaScript Compilado:

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); 

Nota cómo searchParser1 y searchParser2 tienen sus devoluciones de llamada con destino a this y searchParser 's está obligado a Parser.

Como siempre, el botón "Try CoffeeScript" en la página de inicio de CoffeeScript (http://jashkenas.github.com/coffee-script/) es tu amigo.

3

En primer lugar, el concepto del que está hablando no es "alcance", es this, también informalmente llamado el "contexto". Y ciertamente es uno de los conceptos más complicados en JavaScript (y por lo tanto en CoffeeScript), aunque las reglas son bastante simples. Tal vez es porque la palabra this en sí misma, que no parece ser su significado, debe cambiarse tan fácilmente dependiendo de cómo se llame a una función ...

La respuesta de Nicholas es irrelevante, pero le recomiendo que también lea hasta this y tratar de entender realmente, en lugar de simplemente usar => todo el tiempo (es una gran herramienta, pero no siempre la correcta). Unos recursos que recomiendo:

Cuestiones relacionadas