原谅链接:http://www.cnblogs.com/damonlan/archive/2012/07/01/2553425.html

因为这个问题很是经典,而且容易出错,所以在介绍一次。哈哈。莫怪哦。

一。案发现场

我们先看一段很简单的代码:

var v='Hello World';
alert(v);

这个没有疑问吧,弹出“Hello World”。OK,我们继续。

我们在看一段Code:

var v='Hello World';
(function(){
alert(v);
})()

经过运行之后,我们发现,还是和我们预期的一样,弹出了“Hello World”。

好了,有意思的来了。接着在看一段下面的代码:

var v='Hello World';
(function(){
alert(v);
var v='I love you';
})()

如果这个是一个面试题,面试官问你这个结果是多少?你怎么回答?

我们先看结果吧!

结果是 undefined?和你上面自己想的一样吗?

好吧,我就不故弄玄虚了。其实,这里面隐藏了一个陷阱-----JavaScript中的变量提升(Hoisting);

二。深度剖析

现在我来解释下提升是什么意思?顾名思义,就是把下面的东西提到上面。在JS中,就是把定义在后面的东东(变量或函数)提升到前面中定义。

在解释提升之前,我们先来看一下js中的作用域(scoping)问题。

对于JavaScript新手来说scoping是最令人困惑的部分之一。事实上,不仅仅是新手,我遇到或很多有经验的JavaScript程序员也不能完全理解scoping。JavaScript的scoping如此复杂的原因是它看上去非常像C系语言的成员。请看下面的C程序:

#include <stdio.h>
int main() {
int x = 1;
printf("%d, ", x); // 1
if (1) {
int x = 2;
printf("%d, ", x); // 2
}
printf("%d\n", x); // 1
}

这段程序的输出是1,2,1。这是因为在C系语言有块级作用域(block-level scope),当进入到一个块时,就像if语句,在这个块级作用域中会声明新的变量,这些变量不会影响到外部作用域。但是JavaScript却不是这样。在Firebug中试试下面的代码:

 var x = 1;
console.log(x); // 1
if (true) {
var x = 2;
console.log(x); //2
}
console.log(x);// 2

在这段代码中,Firebug显示1,2,2。这是因为JavaScript是函数级作用域(function-level scope)。这和C系语言是完全不同的。块,就像if语句,并不会创建一个新的作用域。只有函数才会创建新的作用域。

对于大部分熟悉C,C++,C#或是Java的程序员来说,这是意料之外并且不被待见的。幸运的是,因为JavaScript函数的灵活性,对于这个问题我们有一个解决方案。如果你必须在函数中创建一个临时的作用域,请像下面这样做:

function foo() {
var x = 1;
if (x) {
(function () {
var x = 2;
// some other code
}());
}
// x is still 1.
}

这种方面确实非常灵活,它使用在任何需要创建一个临时作用域的地方,不仅仅是某个块中。但是,我强烈建议你花点时间好好理解下JavaScript scoping。它实在是非常强力,而且它也是我最喜欢的语言特性之一。如果你很好的理解了scoping,理解hoisting将会更加容易。

2.1变量提升

变量提升,很简单,就是把变量提升提到函数的top的地方。我么需要说明的是,变量提升 只是提升变量的声明,并不会把赋值也提升上来。

比如:

我们定义三个变量:

(function(){
var a='One';
var b='Two';
var c='Three';
})()

实际上它是这样子的:

(function(){
var a,b,c;
a='One';
b='Two';
c='Three';
})()

这个时候就把变量提升了呀。

好,我们现在回到第一段code里面。为什么会报错呢?其实,根据我么根据上面变量提升原件以及js的作用域(块级作用域)的分析,得知 上面代码真正变成如下:

var v='Hello World';
(function(){
var v;
alert(v);
v='I love you';
})()

所以,才会提示说“undefined”。

从这里,我们也学习到,我们在写js code 的时候,我么需要把变量放在函数级作用域的顶端,比如我在上面所举的例子:var a,b,c;。以防止出现意外。

2.2 函数提升

函数提升是把整个函数都提到前面去。

在我们写js code 的时候,我们有2中写法,一种是函数表达式,另外一种是函数声明方式。我们需要重点注意的是,只有函数声明形式才能被提升。

函数声明方式提升【成功】

function myTest(){
foo();
function foo(){
alert("我来自 foo");
}
}
myTest();

函数表达式方式提升【失败】

function myTest(){
foo();
var foo =function foo(){
alert("我来自 foo");
}
}
myTest();

结果如下:

左边报错了。没骗你。

应该到这里基本都可以弄懂了。~

JavaScript中变量提升------Hoisting的更多相关文章

  1. javascript中变量提升的理解

    网上找了两个经典的例子 var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar(); // 10 var ...

  2. JavaScript中变量提升是语言设计缺陷

    首先纠正下,文章标题里的 “变量提升” 名词是随大流叫法,“变量提升” 改为 “标识符提升” 更准确.因为变量一般指使用 var 声明的标识符,JS 里使用 function 声明的标识符也存在提升( ...

  3. Javascript中变量提升的问题

    一.函数声明变量提升 函数声明具有变量提升的问题,所以在函数被声明之前就可以访问. //else中的语句相当于将if中的function重写,因此无论flag为何值,返回的方法始终为重写后的方法. / ...

  4. Javascript中变量提升的问题(五)

    一.函数声明变量提升   函数声明具有变量提升的问题,所以在函数被声明之前就可以访问. console.log(getValue()); function getValue() { return 'a ...

  5. 关于javascript中变量及函数的提升

    javascript中变量以及函数的提升,在我们平时的项目中其实还是挺常用的,尤其是大型项目中,不知不觉就会顺手添加一些变量,而有时候自己的不小心就会酿成一些不必要错误,趁有时间整理一下自己对于js中 ...

  6. JavaScript中变量和函数声明的提升

    现象: 1.在JavaScript中变量和函数的声明会提升到最顶部执行. 2.函数的提升高于变量的提升. 3.函数内部如果用var声明了相同名称的外部变量,函数将不再向上寻找. 4.匿名函数不会提升. ...

  7. JavaScript 中变量、作用域和内存问题的学习

    这是我学习JavaScript的第二篇文章,之前做过几年的Java开发,发现JavaScript虽然也是面向对象的语言但是确实有很多不同之处.就本篇博客,主要学习总结一下最近学习到的JavaScrip ...

  8. JavaScript中变量声明有var和没var的区别

    JavaScript中变量声明有var和没var的区别 JavaScript中有var和没var的区别 Js中的变量声明的作用域是以函数为单位,所以我们经常见到避免全局变量污染的方法是 (functi ...

  9. JavaScript中变量的LHS引述和RHS引用

    JavaScript中变量的LHS引述和RHS引用 www.MyException.Cn  网友分享于:2015-02-04  浏览:0次 JavaScript中变量的LHS引用和RHS引用 在Jav ...

随机推荐

  1. 企业证书安装App

    通过苹果自带的浏览器访问:itms-services:///?action=download-manifest&url=https://www.xxxx.com:xxx/xxxx/xxx.pl ...

  2. PHP程序员应该知道的15个库

    最几年,PHP已经成为最受欢迎的一种有效服务器端编程语言.据2013年发布的一份调查报告显示,PHP语言已经被安装在全球超过2.4亿个网站以及210万台Web服务器之上.PHP代表超文本预处理器,它主 ...

  3. mysql ifnull判断为空设置默认值

    IFNULL(count,0) as count select IFNULL(count,0) as count from table_name 可以设置当某个字段为空的时候默认值.

  4. java web启动后执行初始化任务

    写一个类继承ApplicationListener,可以直接引用下述代码,然后调用相应的方法. package com.linewell.system; import com.linewell.cac ...

  5. Linux IO多路复用之epoll网络编程及源码(转)

    原文: 前言 本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网 ...

  6. ubuntu 下关闭apache服务自动启动

    最近在自己的ubuntu安装了apache服务器,每次开机的时候通过:   ps  -A    命令发现apache服务总是自动启动,如下: 本来自己的电脑内存就小,现在也不用这个服务,所以想让apa ...

  7. Android中 Application的使用

    Application全局唯一,如果需要放置全局的变量,需要用到Application,类似于OC中的单例类,获者OC中的AppDelegate 第一步:创建一个AppContext继承Applica ...

  8. python selenium webdriver处理浏览器滚动条

    用键盘右下角的UP,DOWN按键来处理页面滚动条 这种方法很灵活用起来很方便!!!! from selenium import webdriver import time from selenium. ...

  9. unity3d API汇总

    using UnityEngine; using System.Collections; public class AllFunction : MonoBehaviour { /* API Versi ...

  10. MQTT协议学习研究 & Mosquitto简要教程(安装和使用)

    若初次接触MQTT协议,可先理解以下概念: [MQTT协议特点]——相比于RESTful架构的物联网系统,MQTT协议借助消息推送功能,可以更好地实现远程控制. [MQTT协议角色]——在RESTfu ...