在javascript中替换匿名函数,改变代码执行的方式

时间:2014-04-12 16:42:38

标签: javascript anonymous-function

我有一些我在casperJS中调用的javascript代码,它很短,所以我已经包含了整个列表

var links = []; 
var casper = require('casper').create();

function getLinks() {
  var links = document.querySelectorAll('table');
  return Array.prototype.map.call(links, function(e) {
    return e.getAttribute('id');
  }); 
}

casper.start('example.html', function() {
  links = this.evaluate(getLinks);
});

casper.run(function() {
  this.echo(links.length + ' links found:');
  this.echo(' - ' + links.join('\n - ')).exit();
});

这会输出预期的

3 links found:
 - table A
 - table B
 - table C

切换到getLinks中的匿名函数,以便用以下两个函数替换getLinks

function extract(e) {
  return e.getAttribute('id');
}

function getLinks() {
  var links = document.querySelectorAll('table');
  return Array.prototype.map.call(links, extract);
}

产量

TypeError: 'null' is not an object (evaluating 'links.length')                  
  /Users/jrrpl/git/gamecock/download.js:18
  /usr/local/Cellar/casperjs/1.1-beta3/libexec/modules/casper.js:408 in checkStep

更新

似乎对命名函数的引用导致casper.run()提前执行。有人知道为什么会这样吗?

1 个答案:

答案 0 :(得分:2)

问题在于this.evaluate(getLinks);The docs state

  

基本上PhantomJS’ WebPage#evaluate等效。

     

了解evaluate()

     

这种方法背后的概念可能是最难的   在发现CasperJS时了解。提醒一下,想一想   evaluate()方法作为CasperJS环境和之间的门   你打开的一个页面;每次你把关闭传递给   evaluate(),您正在进入页面并执行代码,就像您一样   使用浏览器控制台。

即使PhantomJS文档也没有声明(更重要的是?我是否错过了?)究竟发生了什么。 The source code虽然非常明确:

page.evaluate = function (func, args) {
    var str, arg, argType, i, l;
    if (!(func instanceof Function || typeof func === 'string' || func instanceof String)) {
        throw "Wrong use of WebPage#evaluate";
    }
    str = 'function() { return (' + func.toString() + ')(';
    for (i = 1, l = arguments.length; i < l; i++) {
        …
        str += JSON.stringify(arg) + ",";
        …
    }
    str = str.replace(/,$/, '') + '); }';
    return this.evaluateJavaScript(str);
};

不,我们也明白为什么要求函数的所有参数都需要序列化:整个事物被转换为一个代码字符串,然后在页面中注入 - &#34;执行就像它被粘贴到控制台&#34;。

这意味着关闭不起作用,最终您将在页面中未定义extract。如果你确实使用了

function getLinks() {
    function extract(e) {
        return e.getAttribute('id');
    }
    var links = document.querySelectorAll('table');
    return Array.prototype.map.call(links, extract);
}

然后它应该工作。