转自:http://www.jb51.net/article/50731.htm
一、全局变量
JavaScript 通过函数管理作用域。在函数内部声明的变量只在这个函数内部,函数外面不可用。另一方面,全局变量就是在任何函数外面声明的或是未声明直接简单使用的。
“未声明直接简单使用”,指的是不用 var 关键字来声明变量。这个我们已经非常清楚,避免造成隐式产生全局变量的方法就是声明变量尽量用 var 关键字。
可你以为用了 var 就 ok 了?来看看这个坑:
function foo() {
var a = b = 0;
// body...
}
也许你期望得到的是两个局部变量,但 b 却是货真价实的全局变量。why? Because 赋值运算是自右往左的 ,所以这相当于:
function foo() {
var a = (b = 0);
// body...
}
所以 b 是全局变量。
填坑:变量声明,最好一个个来,别搞批发~_~;
二、变量声明
先来看坑:
myName = "global";
function foo() {
alert(myName);
var myName = "local";
alert(myName);
}
foo();
乍看上去,我们预计期望两次 alert 的结果分别为 “global” 与 “local”,但真实的结果是 “undefined” 与 “local”。why? Because 变量在同一作用域(同一函数)中,声明都是被提至作用域顶部先进行解析的。
所以以上代码片段的执行行为可能就像这样:
function foo() {
var myName;
alert(myName); // "undefined"
myName = "local";
alert(myName); // "local"
}
用另一个坑来测试下你是否真的理解了预解析:
if (!("a" in window)) {
var a = 1;
}
alert(a);
a 变量的声明被提前到了代码顶端,此时还未赋值。接下来进入 if 语句,判断条件中 "a" in window 已成立(a 已被声明为全局变量),所以判断语句计算结果为 false,直接就跳出 if 语句了,所以 a 的值为 undefined。
var a; // "undefined"
console.log("a" in window); // true
if (!("a" in window)) {
var a = 1; // 不执行
}
alert(a); // "undefined"
填坑:变量声明,最好手动置于作用域顶部,对于无法当下赋值的变量,可采取先声明后赋值的手法。
三、函数声明
函数声明也是被提前至作用域顶部,先于任何表达式和语句被解析和求值的
alert(typeof foo); // "function"
function foo() {
// body...
}
可以对比一下:
alert(typeof foo); // "undefined"
var foo = function () {
// body...
};
明白了这个道理的你,是否还会踩以下的坑呢?
function test() {
alert("1");
}
test();
function test() {
alert("2");
}
test();
运行以上代码片段,看到的两次弹窗显示的都是 “2”,为什么不是分别为 “1” 和 “2” 呢?很简单,test 的声明先于 test() 被解析,由于后者覆盖前者,所以两次执行的结果都是 “2”。
填坑:多数情况下,我用函数表达式来代替函数声明,特别是在一些语句块中。
四、函数表达式
先看命名函数表达式,理所当然,就是它得有名字,例如:
// body...
};
要注意的是:函数名只对其函数内部可见。如以下坑:
var bar = function foo() {
foo(); // 正常运行
};
foo(); // 出错:ReferenceError
填坑:尽量少用命名函数表达式(除了一些递归以及 debug 的用途),切勿将函数名使用于外部。
五、函数的自执行
对于函数表达式,可以通过后面加上 () 自执行,而且可在括号中传递参数,而函数声明不可以。坑:
// (1) 这只是一个分组操作符,不是函数调用!
// 所以这里函数未被执行,依旧是个声明
function foo(x) {
alert(x);
}(1);
以下代码片段分别执行都弹窗显示 “1”,因为在 (1) 之前,都为函数表达式,所以这里的 ()非分组操作符,而为运算符,表示调用执行。
var bar = function foo(x) {
alert(x);
}(1);
// 前面的 () 将 function 声明转化为了表达式
(function foo(x) {
alert(x);
})(1);
// 整个 () 内为表达式
(function foo(x) {
alert(x);
}(1));
// new 表达式
new function foo(x) {
alert(x);
}(1);
// &&, ||, !, +, -, ~ 等操作符(还有逗号),在函数表达式和函数声明上消除歧义
// 所以一旦解析器知道其中一个已经是表达式了,其它的也都默认为表达式了
true && function foo(x) {
alert(x);
}(1);
填坑:这个坑的关键在于,弄清楚形形色色函数表达式的实质。
六、循环中的闭包
以下演示的是一个常见的坑:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h3>when clicking links below, show the number of its sequence</h3>
<ul>
<li><a href="#">link #0</a></li>
<li><a href="#">link #1</a></li>
<li><a href="#">link #2</a></li>
<li><a href="#">link #3</a></li>
<li><a href="#">link #4</a></li>
</ul>
</body>
</html>
var links = document.getElementsByTagName("ul")[0].getElementsByTagName("a");
for (var i = 0, l = links.length; i < l; i++) {
links[i].onclick = function (e) {
e.preventDefault();
alert("You click link #" + i);
}
}
我们预期当点击第 i 个链接时,得到此序列索引 i 的值,可实际无论点击哪个链接,得到的都是 i 在循环后的最终结果:”5”。
解释一下原因:当 alert 被调用时,for 循环内的匿名函数表达式,保持了对外部变量 i的引用(闭包),此时循环已结束,i 的值被修改为 “5”。
填坑:为了得到想要的结果,需要在每次循环中创建变量 i 的拷贝。以下演示正确的做法:
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h3>when clicking links below, show the number of its sequence</h3>
<ul>
<li><a href="#">link #0</a></li>
<li><a href="#">link #1</a></li>
<li><a href="#">link #2</a></li>
<li><a href="#">link #3</a></li>
<li><a href="#">link #4</a></li>
</ul>
</body>
</html>
var links = document.getElementsByTagName(“ul”)[0].getElementsByTagName(“a”);
for (var i = 0, l = links.length; i < l; i++) {
links[i].onclick = (function (index) {
return function (e) {
e.preventDefault();
alert("You click link #" + index);
}
})(i);
}
可以看到,(function () { ... })() 的形式,就是上文提到的 函数的自执行 ,i 作为参数传给了 index,alert 再次执行时,它就拥有了对 index 的引用,此时这个值是不会被循环改变的。当然,明白了其原理后,你也可以这样写:
for (var i = 0, l = links.length; i < l; i++) {
(function (index) {
links[i].onclick = function (e) {
e.preventDefault();
alert("You click link #" + index);
}
})(i);
}
It works too.
相关推荐
JavaScript是一个神奇的语言,字符串转数字有5种方法,各有各的坑法!接下来通过本文给大家介绍JavaScript字符串转数字的5种方法及其陷阱,感兴趣的朋友一起看看吧
map转json
前言 刚接到这个需求的时候,觉得很简单(的确很简单)但是这玩意的坑真的也让人无奈。 网上找了很多的资料,都没有写出痛点(这就很难过了)。通过实践并且在我们项目中平稳运行,想分享给后面的人 我的博客上...
在Android studio中最新sdk中成功完成了java和javascript之间的互调,原谅我要1分,因为我花了半天时间才搞定,解决了一些坑。android端提供json数据,在浏览器(webView显示的)中通过table+js显示数据,并实现了...
JS 类型转换规则总结JS 隐射类型转换// 会输出100 + 问题parseInt 的坑1 与 Number(1)有什么区别// Number {[[Prim
使用TypeScript能够避免在原生JavaScript上开发所带来的弱类型语言的坑。(我该输入啥?调用后返回啥?哎还是看看源码吧。。。) 嗯!很好,强类型的JavaScript,挺好的。但是,我舍不得那NPM里众多库无微不至的人文...
(1)MQTT.js 一个 MQTT 协议的客户端库,用 JavaScript 编写,可用于 Node.js 和浏览器。在 Node.js 端可以通过全局安装使用命令行连接,同时还支持 MQTT ,MQTT TLS 证书连接;值得一提的是 MQTT.js 还对微信小...
转到项目中的“编辑设置”,然后将重定向URI设置为并保存 克隆此GitHub存储库或下载ZIP文件。 本示例将其保存到您的桌面: cd Desktop git clone https://github.com/ajmeese7/smoke-pit-playlist.git cd smoke-pit...
公司有个业务需求,要求后台传pdf的base64编码给前端,前端显示到界面上,后来在网上搜索了很多关于base64转pdf的文章,都写的不是非常的详细,在实现的过程中遇到很多坑,经过一天的研究终于实现了这个功能,分享一下我在...
采坑系列 Antd 的 Radio 组件文字显示,默认不支持换行; 解决:css override .ant-radio-wrapper { white-space: normal; } Excel 文件经过转换 JSON 数据格式中,Date 日期类数据会被转换成起始于1899年11月30...
嗯,挖坑无止境,填坑看心情 安装 由于Nodejieba使用了Node C++扩展,所以你可能需要先安装相关依赖,如已配置可以忽略此步骤: sudo apt install make sudo apt install g++ sudo npm install node-gyp -g 安装...
框架用的是,在用和 px2rpx-loader 分别转换单位之后,发现这种组件动态传参变换 style 是不支持预转换的,所以这就可能导致我们不能自由的根据设计稿编写 px 了,但是为了团队中小伙伴能愉快的开发,只能一步步采坑了。...
本文旨在记录“WebRTC实现服务器中转模式的多人实时通话”项目的完整实施过程,方便想要实现类似功能的人能够复刻我们的经验,少走点弯路、少踩点坑,将精力投入到定制开发符合自身产品特点的功能上。 本文假定读者...
wx2my 支付宝微信小程序互转先挖个坑,填不填得上,看自己本事吧目前功能只能修改文件扩展名,api还没想好怎么处理使用方法 node wx2my.js + 参数 参数目前只支持 wx2my 和 my2wx,顾名思义一个是微信转支付宝一个是...
移动端填坑 {基本设置,初始化reset} 图片预览及转base64 {兼容处理} 日期格式化 {日期格式化yyyy-MM-dd HH:mm:ss} 生成二维码 {日期格式化yyyy-MM-dd HH:mm:ss} redux {redux实践} 其它项目Demo angular1 豆瓣电影 ...
#rolling-music hackathon做出的小东西 (2015‘5’23) 一个简单的用手机控制电脑做出React的小游戏。...已挖坑,不填(你来打我啊:grinning_face_with_smiling_eyes:) 因为我们目前有一个更好的idea。
ExtendScript-Helper 该库中代码用于开发Photoshop等Adobe系列工具的插件 NOTE: 代码均基于PhotoShop CC 2017版本,其他版本没有验证 artboard.jsx ...使用progressbar的坑,具体参考progressbar.md文件
吐槽p2egret支持的p2虽然方便,但是坑太多,刚体碰撞出错,刚体穿透时常发生,社区也不活跃,资料少,还因为物理效果欠佳,搞得本人的单子凉了,煮熟的鸭子飞了。实在是气不过,不过不去寻求新的物理引擎,那么...
转react-native也有一年多了(前两年一直在用vue),一直在做混合APP开发,半年前做了一个纯rn的项目,继承了两个版本,由于受市场影响,公司将其下线了,个人抽时间将项目的基本架构的代码分解成倍,为了自我提升独...
如果你会js,node,你将很容易玩转这个项目!因为我已经给你搭好架子了。(踩了超多坑!!! 最后:如果你喜欢live2d,喜欢这个项目,欢迎fork,反馈,一定第一时间解答! 环境 chrome 83.0.4103.64 node 12.14.1 ...