[Effective JavaScript 笔记]第15条:当心局部块函数声明笨拙的作用域
嵌套函数声明。没有标准的方法在局部块里声明函数,但可以在另一个函数的顶部嵌套函数声明。
function f(){return "global"}
function test(x){
var result=[];
function f(){return "local";}//block-local
if(x){
result.push(f());
}
result.push(f());
return result;
}
test(true);//["local","local"]
test(false);//["local"]
如果我们把函数f移动到局部块里。
function f(){return "global"}
function test(x){
var result=[];
if(x){
function f(){return "local";}//block-local
result.push(f());
}
result.push(f());
return result;
}
test(true);//?
test(false);//?
js没有块级作用域,所以内部函数f的作用域应该是整个test函数。下面的这个例子的合理猜测结果是["local","local"]和["local"]。事实上,一些js环境的确如此执行。并不是所有js环境都这样,其他一些环境在运行时根据包含函数f的块是否被执行来有条件地绑定函数f。(这使代码更难理解,而且致使性能降低)
下面为chrome控制台的执行结果: 
关于这点ES标准中几乎没有定义。ES5,js标准才承认局部块函数声明的存在。官方指定函数声明只能出现在其他函数或者程序的最外层。ES5建议把在非标准环境的函数声明转变成警告或错误。
一些js实现在严格模式下将这类函数报告为错误(具有局部块函数声明的处于严格模式下的程序报告一个语法错误)。有助于检测出不可移植的代码,并为未来的标准版本给局部块函数声明指定更明智和可移植的主义开辟了一条路。
编写可移植的函数的最好方式是始终避免将函数声明置于局部块或子语句中。
如果你想写嵌套函数声明,应该将它置于其父函数的最外层,如示例1,如果需要有条件的选择函数,最好的方法是使用var声明和函数表达式来实现。
function f(){return "global";}
function test(x){
var g=f,result=[];
if(x){
g=function(){return "local";}
result.push(g());
}
result.push(g());
return result;
}
消除内部变量作用域的神秘性。无条件地作为局部变量绑定,而仅仅只有赋值语句是有条件的。
提示
始终将函数声明置于程序或被包含的函数的最外层以避免不可移植的行为
使用var声明和有条件的赋值语句替代有条件的函数声明
[Effective JavaScript 笔记]第15条:当心局部块函数声明笨拙的作用域的更多相关文章
- [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法
js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...
- [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象
js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...
- [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符
“1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...
- [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码
函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...
- [Effective JavaScript 笔记]第66条:使用计数器来执行并行操作
第63条建议使用工具函数downloadAllAsync接收一个URL数组并下载所有文件,结果返回一个存储了文件内容的数组,每个URL对应一个字符串.downloadAllAsync并不只有清理嵌套回 ...
- [Effective JavaScript 笔记]第16条:避免使用eval创建局部变量
js中的eval函数是一个强大.灵活的工具.强大的工具容易被滥用,所以了解是值得的.(本人只用过它来处理json数据).错误使用eval函数的方式一:允许它干扰作用域.调用eval函数会将其参数作为j ...
- [Effective JavaScript 笔记]第51条:在类数组对象上复用通用的数组方法
前面有几条都讲过关于Array.prototype的标准方法.这些标准方法被设计成其他对象可复用的方法,即使这些对象并没有继承Array. arguments对象 在22条中提到的函数argument ...
- [Effective JavaScript 笔记] 第13条:使用立即调用的函数表达式创建局部作用域
function wrapElements(a){ var res=[],i,n; for(i=0,n=a.length;i<n;i++){ res[i]=function(){return a ...
- [Effective JavaScript 笔记]第63条:当心丢弃错误
管理异步编程的一个是错误处理.同步代码中只要使用try语句块包装一段代码很容易一下子处理所有的错误. try{ f(); g(); h(); } catch(e){ //这里用来下得出现的错误 } t ...
随机推荐
- 千万不要在JS中使用连等赋值操作
前言 文章标题这句话原本是在国外某JavaScript规范里看到的,当时并没有引起足够的重视,直到最近一次出现了bug发现JS里的连等赋值操作的特色(坑). 网上搜索一番发现一个非常好的连等赋值的(来 ...
- Java server数据之(4):Redis鸟瞰
Redis简介 Redis是NoSQL数据库中的一种,属于key-value键值对这一个子类别. 它常被称作是一款数据结构服务器(data structure server). Redis中的数据结构 ...
- jQuery使用之(三)处理页面的元素
对于页面的元素,在DOM编程中可以通过各种查询.修改手段进行管理,非常麻烦.jQuery提供了一整套的方法来处理页面的元素.包括元素的内容.复制.移动和替换等.本节将介绍一些常用的内容. 1.直接获取 ...
- Android音乐播放器的开发实例
本文将引导大家做一个音乐播放器,在做这个Android开发实例的过程中,能够帮助大家进一步熟悉和掌握学过的ListView和其他一些组件.为了有更好的学习效果,其中很多功能我们手动实现,例如音乐播放的 ...
- Nginx下用webbench进行压力测试
在运维工作中,压力测试是一项非常重要的工作.比如在一个网站上线之前,能承受多大访问量.在大访问量情况下性能怎样,这些数据指标好坏将会直接影响用户体验. 但是,在压力测试中存在一个共性,那就是压力测试的 ...
- 0505-NABCD模型、视频
1.确定选题. 应用NABCD模型,分析你们初步选定的项目,充分说明你们选题的理由. 录制为演说视频,上传到视频网站,并把链接发到团队博客上. 截止日期:2016.5.6日晚10点 NABCD模型: ...
- vijos p1523 贪吃的九头龙 思考思考再思考,就荒废了4小时
树形DP要有自己的风格,转二叉树是基础,考虑边界最头疼. #include<cstdio> #include<cstring> #include<algorithm> ...
- UVA 10391 stl
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- java时间库Joda-Time
虽然在java8里面有内置的最新的时间库,但是在java8之前的版本所有的时间操作都得自己写,未免有些繁琐,如果我们不自己封装的话可以用Joda-Time这个时间库,下面写下这个库的具体用法. git ...
- 新建的 web 工程 有红色的惊叹号
新建的 web 工程 有红色的感叹号问题: 在eclipse 中新建一个web工程,但是工程上有红色的感叹号.解决: 1.右键工程,选择Build Path-->Configur ...