Node.js全局变量和带方括号的函数 - 为什么这有效?

时间:2015-12-19 21:51:17

标签: javascript node.js variables brackets

我有一个模块,它将对象返回给具有以下伪代码结构的回调:

module.exports=function(){

global.foo=function(){
  var callbacks=Array.prototype.slice.call(arguments,1);
  var conf=arguments[0];
  return global[callbacks.shift()].apply(null,[conf,callbacks]);
 }

global.bar=function(){
  var callbacks=Array.prototype.slice.call(arguments,1);
  var conf=arguments[0];
  return global[callbacks.shift()].apply(null,[conf,callbacks]);
 }

// This one is where i ran into trouble
global.foobar=function(){
  var callbacks=Array.prototype.slice.call(arguments,1);
  var conf=arguments[0];
  // right here
  if(callbacks.length===[].length){
     return global[callbacks.shift()].apply(null,[conf,callbacks]);
 }
}
var conf={'pseudo':'object'};   
return global['foo'](conf,'foo','bar','foobar');
}

foobar之前一切正常,发生的事情就是当我开始检查是否还有回调时 - 因为如果它们是,我想打电话给它们 - callbacks.length是1点。这对我来说没有意义,我发现那时callbacks实际上等于[[]]。我不知道为什么要归还,所以我想我有两个问题。任何人都可以看到为什么callbacks等于[[]]

我在此过程中发现的是,在全局命名空间中使用称为函数的字符串时 - 如var bar='foo'; global[bar]()调用global.foo() - 忽略多个括号。例如,global[[[[[[['foo']]]]]]] === global['foo']。还奇怪(至少对我而言),以下内容:

// With 
global.bar='foo';
global.foo=function(){return true;}
//the following
global[global[bar]]()
// throws a TypeError: undefined is not a function

这些对我来说都没有意义。

我认识到这个问题最终会提出三个问题,并且有点混乱,但坦率地说,我有点困惑,而且我不确定我想问我想知道什么,所以我只是说了一切。

我的主要问题是关于多个括号,以及为什么有效。

由于

1 个答案:

答案 0 :(得分:4)

  

我的主要问题是关于多个括号,以及为什么   的工作原理。

多个括号的作用只是因为它试图进行字符串转换以获取属性名称。因此,无论您拥有多少嵌套数组,它最终都会在每个数组上调用.toString(),因为内部数组只有一个包含字符串的项目,所以多个.toString()调用最终结束解析为内部字符串。

以下是浏览器中相同概念的演示:

window.foo = "hi"
document.write(window[[[[["foo"]]]]]);

进一步解释:

["foo"].toString() === "foo";

那么,那么:

[["foo"].toString()].toString() === "foo"

但是,如果外部.toString()存在,那么它已经将字符串驱动到字符串中,因此您可以移除内部.toString(),从而得到:

[["foo"]].toString() === "foo"

然后,只要外层的东西将它驱动到一个字符串,你就可以根据需要将它嵌套多个级别。

并且,因为属性名称始终是字符串,所以:

global[[[[[[['foo']]]]]]] 

您最终要求查找可以在global对象上查找的属性名称,因为属性名称是一个字符串,在外部数组上调用.toString()。当外部数组将它的唯一项目转换为字符串时,它会要求一个项目将自身转换为字符串,这样:

global[[[[[[['foo']]]]]]] 

变成了这个:

global[[[[[[['foo'].toString()].toString()].toString()].toString()].toString()].toString()] 

这有希望解释为什么你最终只能得到这个:

global["foo"]

仅供参考,如果您查看Array.prototype.toString()的ES5 / ES6规范,它最终会调用array.join(),对于单个元素数组,它最终会对该单个元素执行.toString()这就是它如何导致所有嵌套数组自己调用.toString()。外部数组在第一个嵌套数组上调用.toString(),在它的单个项目上调用.toString(),这是下一个嵌套数组,依此类推,直到它最终到达从所有{返回的内部字符串的内部字符串{1}}来电。并且,重要的不是它嵌套了多少个数组。

.toString()的规范参考:http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.tostring

Array.prototype.toString()调用的Array.prototype.join()的规范参考:http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.join

在你的另一个场景中:

Array.prototype.toString()
  

这些对我来说都没有意义。

以下是// With global.bar='foo'; global.foo=function(){return true;} //the following global[global[bar]]() // throws a TypeError: undefined is not a function 一次发生的事情:

global[global[bar]]()解析为字符串bar

因此,'foo'会解析为global[bar],这是您的职能。

但是,然后你尝试对它进行另一个全局引用,就像这个global['foo']一样,那么你基本上是在尝试:

global[global[bar]]

global[yourfunction]

这将尝试将您的函数转换为字符串并在global[global.foo] 对象上查找该属性。那将是global。因此,您将尝试执行undefined这是一个TypeError,因为undefined()不是函数。

在这种情况下将起作用的是:

undefined