这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
这篇文章主要给大家介绍了关于 Javascript 变量的相关问题,文中给出了详细的介绍和示例代码,相信对大家的理解和学习具有一定的参考借鉴价值,有需要的朋友们下面来一起看看吧。
前言
再说本文的内容之前,我们先回溯到 1995 年,当 Brendan Eich 在设计第一版 JavaScript 时,他搞错了许多东西,当然这也包括曾属于语言本身的一部分,例如 Date 对象,对象相乘被自动转换为 NaN 等。然而现在回过头看,语言最重要的部分都是设计合理的:对象、原型、具有词法作用域的一等函数、默认情况下的可变性等。语言的骨架非常优秀,甚至超越了人们对它的初步印象。
话说回来,正是 Brendan 当初的设计错误才诞生了今天这篇文章。我们这次关注的目标非常小,在你使用这门语言多年后可能根本不会注意到这个问题,但是它又如此重要,因为我们可能会误认为这个错误就是语言设计中的 "the good parts"(译者注:请参考《JavaScript 语言精粹》一书中附录 A:毒瘤中有关作用域的描述)。
今天我们一定要把这些与变量有关的问题拿下。
问题 #1:JS 没有块级作用域
请看这样一条规则:在 JS 函数中的 var 声明,其 作用域 是函数体的全部。乍一听没什么问题,但是如果碰到以下两种情况就不会得到令人满意的结果。
其一,在代码块内声明的变量,其作用域是整个函数作用域而不是块级作用域。
你之前可能没有关注到这一点,但我担心这个问题确实是你不能够轻易忽视的。我们一起重现一下由这个问题引发的 bug。
假如你现在的代码使用了一个变量 t:
- function runTowerExperiment(tower, startTime) {
- var t = startTime;
- tower.on("tick", function () {
- ... 使用了变量t的代码 ...
- });
- ... 更多代码 ...
- }
到目前为止,一切都很顺利。现在你想添加测量保龄球速度的功能,所以你在回调函数内部添加了一个简单的 if 语句。
- function runTowerExperiment(tower, startTime) {
- var t = startTime;
- tower.on("tick", function () {
- ... 使用了变量t的代码 ...
- if (bowlingBall.altitude() <= 0) {
- var t = readTachymeter();
- ...
- }
- });
- ... 更多代码 ...
- }
哦,亲爱的,之前那段 "使用了变量 t 的代码" 运行良好,现在你无意中添加了第二个变量 t,这里的 t 指向的是一个新的内部变量 t 而不是原来的外部变量。
JavaScript 中 var 声明的作用域像是 Photoshop 中的油漆桶工具,从声明处开始向前后两个方向扩散,直到触及函数边界才停止扩散。你想啊,这种变量 t 的作用域甚广,所以一进入函数就要马上将它创建出来。这就是所谓的提升(hoisting)。变量提升就好比是,JS 引擎用一个很小的代码起重机将所有 var 声明和 function 函数声明都举起到函数内的最高处。
现在看来,提升特性自有它的优点。如果没有提升的动作,许多在全局作用域范围内看似合理的完美技术在立即调用函数表达式( IIFE )中通通失效。但在上面演示的这种情况下,提升会引发令人不愉快的 bug:所有使用变量 t 进行的计算最终的结果都是 NaN。这种问题极难定位,尤其是当你的代码量远超上面这个玩具一般的示例,你会发狂到崩溃。
在原有代码块之前添加新的代码块会导致诡异的错误,这时候我就会想,到底是谁的问题,我的还是系统的?我们可不希望自己搞砸了系统。
而这个问题与接下来这个问题相比就相形见绌了。
问题 #2:循环内变量过度共享
你可以猜一下当执行以下这段代码时会发生什么,非常简单:
- var messages = ["嗨!", "我是一个web页面!", "alert()方法非常有趣!"];
- for (var i = 0; i < messages.length; i++) {
- alert(messages[i]);
- }
如果你一直跟随这个专栏的文章,你知道我喜欢在示例代码中使用
方法。可能你也知道
- alert()
不是一个好的 API,它是一个同步方法,所以当弹出一个警告对话框时,输入事件不会触发,你的 JS 代码,包括你的整个 UI,直到用户点击 OK 确认之前完全处于暂停状态。
- alert()
请不要轻易使用
来实现 Web 页面中的功能,我之所以在代码中使用是因为
- alert()
特性使它变成一个非常有教学意义的工具。
- alert()
而且,如果放弃所有笨重的方法和糟糕的行为就可以做出一只会说话的猫,何乐而不为呢?
- var messages = ["喵!", "我是一只会说话的猫!", "回调(callback)非常有趣!"];
- for (var i = 0; i < messages.length; i++) {
- setTimeout(function() {
- cat.say(messages[i]);
- },
- i * 1500);
- }
然而一定是哪里不对,这只会说话的猫并没有按照预期连说三条消息,它说了三次 "undefined"。
你知道问题出在哪里么?
来源: http://www.phperz.com/article/17/0611/328300.html