我有一个模块,它将对象返回给具有以下伪代码结构的回调:
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
这些对我来说都没有意义。
我认识到这个问题最终会提出三个问题,并且有点混乱,但坦率地说,我有点困惑,而且我不确定我想问我想知道什么,所以我只是说了一切。
我的主要问题是关于多个括号,以及为什么有效。
由于
答案 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