CoffeeScript 作用域问题

5

我在这里做错了什么?我在我的回调函数中使用了fat arrows =>,但是当代码到达cb.onEndElement并调用@returner时,我会得到一个null对象异常。那么为什么@returner不存在?

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

我的回答解决了你的问题吗? - nicolaskruchten
2个回答

5

你的方法 search 需要使用胖箭头 => 来将其绑定到 Parser 实例。

此外,尽管行 searchParser: new xml.SaxParser (cb) => 可以编译通过,但它可能并不是您想要的,因为胖箭头将回调函数绑定到了 Parser 而不是 this。您有两个选择:

  1. 鉴于您的调用方式,您应该在构造函数中放置 @searchParser = new xml.SaxParser (cb) => ...
  2. 否则,您可以使用 searchParser: () => new xml.SaxParser (cb) => 并在下面使用括号来调用它:@searchParser().parseString str,这将创建一个绑定到 thissearchParser 方法。

以下是我的两个解决方案、稍微简化的原始代码以及已编译的代码,供比较和对照使用:

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代码:

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

请注意,searchParser1searchParser2的回调函数绑定到this,而searchParser的回调函数则绑定到Parser
像往常一样,在CoffeeScript主页(http://jashkenas.github.com/coffee-script/)上有一个“尝试CoffeeScript”按钮可以帮助您!

3
首先,你所说的概念不是“范围”,而是this,也被非正式地称为“上下文”。尽管规则相当简单,但这绝对是JavaScript(因此也是CoffeeScript)中最棘手的概念之一。也许是因为this这个词本身,它的意思似乎不应该因函数调用方式的不同而轻易改变...
Nicholas的答案非常准确,但我建议你也要研究this并尝试真正理解它,而不仅仅是一直使用=>(这是一个很好的工具,但并不总是正确的)。我推荐一些资源:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接