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

Node.js global variables and functions with square brackets - why does this work?

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

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

None 对我来说很有意义。

我知道这个问题最后问了三个问题,有点乱,但坦白说我有点糊涂,我不太确定我想问我想知道的东西,所以我什么都说了。

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

谢谢

My main questions is regarding the multiple brackets, and why that works.

多个括号之所以有效,是因为它试图进行字符串转换以获得 属性 名称。因此,无论您有多少个嵌套数组,它最终都会在每个数组上调用 .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(),这是下一个嵌套数组,依此类推,直到它最终到达从所有 .toString()来电。而且,嵌套的数组深度并不重要。

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

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


在你这里的其他场景中:

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

None of that makes sense to me.

这是 global[global[bar]]() 一次一件的情况:

bar 解析为字符串 'foo'.

因此,global[bar] 解析为 global['foo'],这是您的函数。

但是,然后你尝试像这样对它做另一个全局引用 global[global[bar]],那么你实际上是在尝试做:

global[yourfunction]

global[global.foo]

这将尝试将您的函数转换为字符串并在 global 对象上查找 属性。那将是 undefined。因此,您将尝试执行 undefined() 这是一个类型错误,因为 undefined 不是函数。

在这种情况下有效的是:

global[bar]()