深入理解JavaScript系列(2):揭秘命名函数表达式(4)
通过查看调用栈的信息,我们可以很明了地知道foo调用了bar, bar又调用了baz(而foo本身有在expr_test.html文档的全局作用域内被调用),不过,还有一个比较爽地方,就是刚才说的Firebug为匿名表达式取名的功能:
function foo(){ return bar(); } var bar = function(){ return baz(); } function baz(){ debugger; } foo(); // Call stack baz bar() //看到了么? foo expr_test.html()复制代码
然后,当函数表达式稍微复杂一些的时候,调试器就不那么聪明了,我们只能在调用栈中看到问号:
function foo(){ return bar(); } var bar = (function(){ if (window.addEventListener) { return function(){ return baz(); }; } else if (window.attachEvent) { return function() { return baz(); }; } })(); function baz(){ debugger; } foo(); // Call stack baz (?)() // 这里可是问号哦 foo expr_test.html()复制代码
另外,当把函数赋值给多个变量的时候,也会出现令人郁闷的问题:
function foo(){ return baz(); } var bar = function(){ debugger; }; var baz = bar; bar = function() { alert('spoofed'); }; foo(); // Call stack: bar() foo expr_test.html()复制代码
这时候,调用栈显示的是foo调用了bar,但实际上并非如此,之所以有这种问题,是因为baz和另外一个包含alert('spoofed')的函数做了引用交换所导致的。
归根结底,只有给函数表达式取个名字,才是最委托的办法,也就是使用命名函数表达式。我们来使用带名字的表达式来重写上面的例子(注意立即调用的表达式块里返回的2个函数的名字都是bar):
function foo(){ return bar(); } var bar = (function(){ if (window.addEventListener) { return function bar(){ return baz(); }; } else if (window.attachEvent) { return function bar() { return baz(); }; } })(); function baz(){ debugger; } foo(); // 又再次看到了清晰的调用栈信息了耶! baz bar foo expr_test.html()复制代码
OK,又学了一招吧?不过在高兴之前,我们再看看不同寻常的JScript吧。
JScript的Bug
比较恶的是,IE的ECMAScript实现JScript严重混淆了命名函数表达式,搞得现很多人都出来反对命名函数表达式,而且即便是最新的一版(IE8中使用的5.8版)仍然存在下列问题。
下面我们就来看看IE在实现中究竟犯了那些错误,俗话说知已知彼,才能百战不殆。我们来看看如下几个例子:
相关新闻>>
- Javascript 兼容 IE6、IE7、FF 的“加入收藏”“设为首页”
- 好好学一遍JavaScript 笔记(一)——基础中的基础
- 好好学一遍JavaScript 笔记(二)——encode、数组、对象创建
- 好好学一遍JavaScript 笔记(三)——StringBuffer、prototype
- 好好学一遍javaScript 笔记(四)——Attribute、HTML元素、文档碎
- 好好学一遍JavaScript 笔记(五)——正则表达式基础
- 好好学一遍JavaScript 笔记(六)——正则表达式基础二
- 好好学一遍JavaScript 笔记(七)——RegExp对象与常用正则
- 好好学一遍JavaScript 笔记(八)——冒泡型事件、捕获型事件
- JavaScript详解
- 发表评论
-
- 最新评论 更多>>