在以下示例中:http://jsfiddle.net/maniator/ScTAW/4/
我有这个js:
var storage = (function () {
var store = [];
return {
"add": function (item) {
store.push(item);
},
"get": function () {
return store;
}
};
}());
storage.add('hi there')
console.log(storage, storage.get(), storage.add('hi there #2'));
以下是打印到控制台的内容:
对象 [“hi there”,“hi there#2”] undefined
有人会认为控制台应该只说:
对象 [“hi there”] undefined
因为第二次推送在记录值之后才发生不,因此不应显示。
在以下示例中:http://jsfiddle.net/maniator/ScTAW/5/
我正在使用相同的storage
变量,但我记录如下:
storage.add('hi there')
console.log(storage, storage.get(), (function() {
storage.add('hi there #2');
console.log('TESTING');
})());
打印到控制台的内容是:
嗯,这很奇怪现在不是吗?人们可以期待看到:TESTING
宾语 [“hi there”,“hi there#2”] undefined
对象 [“hi there”] undefined
测试
为什么会这样?控制台日志记录机制幕后发生了什么?
答案 0 :(得分:18)
在大多数(如果不是全部)命令式编程语言中,必须在调用函数之前评估传递给函数调用的任何参数(所谓的Eager evaluation)。此外,它们通常按从左到右的顺序进行评估(对于C,例如它未定义),但是在两个示例中,参数的计算顺序无关紧要。在查看详细情况时,这应该是非常明显的:
如前所述,在调用console.log
之前,必须先执行storage.get()
,然后返回store
数组。然后storage.add('hi there #2')
将被执行(或反过来),因此其结果(在这种情况下为undefined
,因为add
不返回任何内容)可以作为第三个参数传递给{ {1}}。这意味着将使用参数console.log
调用一次console.log
,(storage, storage.store, undefined)
数组已经包含“hi there#2”,从而产生您观察到的结果。
在第二个例子中,推理再次相同,函数调用稍微模糊一些。首先看它看起来有一个函数作为第3个参数传递给store
函数;但它实际上是一个函数调用(观察者最后是console.log
)。因此()
将被执行,然后storage.add('hi there #2')
,然后匿名函数执行的console.log('TESTING')
结果将再次传递给undefined
。
如果您确实将函数传递给console.log
,它将打印该函数定义,而不执行任何操作。所以:
console.log
,最后没有storage.add('hi there')
console.log(storage, storage.get(), (function() {
storage.add('hi there #2');
console.log('TESTING');
}));
,结果为:
()
我希望这会让事情变得更加清晰。
答案 1 :(得分:2)
当你像这样打电话给console.log
时
console.log(storage, storage.get(), storage.add('hi there #2'));
评估 storage.add('hi there #2')
,并将 返回值 传递给console.log
。评估它会导致数组项立即添加到store
。
与storage.get()
相同的事情 - > store
。如此有效,声明变为:
console.log(storage, store, [return value of add which is undefined]);
打印时,会评估store
并输出其内容,这就是您看到["hi there", "hi there #2"]
在第二个例子中,首先评估匿名函数并传递结果。
答案 2 :(得分:1)
console.log
的所有参数将首先被迭代和评估,以便汇编输出。在迭代您传递的参数时,会对对象进行更改并调用函数。 后,记录器迭代了参数,输出数据。
因为对象是byRef,所以storage.store
对象的“第二个参数”更改会反映在控制台输出中。因为参数是迭代的,所以最后一个参数中的函数调用在输出汇编之前被称为,所以在看到第一个console.log
的输出之前,你会看到函数调用的输出。调用
值得注意的是,console.log
的输出不会显示调用console.log
时存在的对象。在对象的情况下,实际获得的是对象的引用句柄。因此,在将句柄添加到console.log
的输出后对对象所做的任何更改仍将反映在对象本身中。由于句柄仅指向对象本身,因此您不会获得显示对象状态的输出,就像调用函数时一样,而是显示对象的实时链接,因为它现在是 。
答案 3 :(得分:1)
在 console.log
被称为之前,完全评估了存储添加功能,因为它是一个参数。
这不是console.log
特有的,这就是每种命令式编程语言的工作方式。