在javascript中, 理解变量的作用域以及变量提升是非常有必要的。这个看起来是否很简单,但其实并不是你想的那样,还要一些重要的细节你需要理解变量作用域
“一个变量的作用域表示这个变量存在的上下文。它指定了你可以访问哪些变量以及你是否有权限访问某个变量。”

变量作用域分为局部作用域和全局作用域。

局部变量(处于函数级别的作用域)
不像其他对面对象的编程语言(比方说C++,Java等等),javascript没有块级作用域(被花括号包围的);当是,javascript有拥有函数级别的作用域,也就是说,在一个函数内定义的变量只能在函数内部访问或者这个函数内部的函数访问(闭包除外,这个我们过几天再写个专题)。

函数级别作用域的一个例子:

复制代码代码如下:
var name = "Richard";

function showName () {
    var name = "Jack"; // local variable; only accessible in this showName function
    console.log (name); // Jack
}
console.log (name); // Richard: the global variable

没有块级作用域:

复制代码代码如下:
var name = "Richard";
// the blocks in this if statement do not create a local context for the name variable
if (name) {
    name = "Jack"; // this name is the global name variable and it is being changed to "Jack" here
    console.log (name); // Jack: still the global variable
}

// Here, the name variable is the same global name variable, but it was changed in the if statement
console.log (name); // Jack

//    不要忘记使用var关键字
//    如果声明一个变量的时候没有使用var关键字,那么这个变量将是一个全局变量!
// If you don't declare your local variables with the var keyword, they are part of the global scope
var name = "Michael Jackson";

function showCelebrityName () {
    console.log (name);
}

function showOrdinaryPersonName () {    
    name = "Johnny Evers";
    console.log (name);
}
showCelebrityName (); // Michael Jackson
// www.jbxue.com 
// name is not a local variable, it simply changes the global name variable
showOrdinaryPersonName (); // Johnny Evers

// The global variable is now Johnny Evers, not the celebrity name anymore
showCelebrityName (); // Johnny Evers

// The solution is to declare your local variable with the var keyword
function showOrdinaryPersonName () {    
    var name = "Johnny Evers"; // Now name is always a local variable and it will not overwrite the global variable
    console.log (name);
}
//    局部变量优先级大于全局变量
//如果在全局作用域中什么的变量在局部作用域中再次声明,那么在局部作用域中调用这个变量时,优先调用局部作用域中声明的变量: 
var name = "Paul";

function users () {
    // Here, the name variable is local and it takes precedence over the same name variable in the global scope
var name = "Jack";

// The search for name starts right here inside the function before it attempts to look outside the function in the global scope
console.log (name); 
}

users (); // Jack

全局变量
所有在函数外面声明的变量都处于全局作用域中。在浏览器环境中,这个全局作用域就是我们的Window对象(或者整个HTML文档)。

每一个在函数外部声明或者定义的变量都是一个全局对象,所以这个变量可以在任何地方被使用,例如:

复制代码代码如下:
// name and sex is not in any function
var myName = "zhou";
var sex = "male";

//他们都处在window对象中
console.log(window.myName); //paul
console.log('sex' in window); //true

如果一个变量第一次初始化/声明的时候没有使用var关键字,那么他自动加入到全局作用域中。

复制代码代码如下:
function showAge(){
  //age初始化时没有使用var关键字,所以它是一个全局变量
  age = 20;
  console.log(age);
}

showAge();  //20
console.log(age); //因为age是全局变量,所以这里输出的也是20

setTimeout中的函数是在全局作用域中执行的

setTimeout中的函数所处在于全局作用域中,所以函数中使用this关键字时,这个this关键字指向的是全局对象(Window):

复制代码代码如下:
var Value1 = 200;
var Value2 = 20;
var myObj = {
  Value1 : 10,
  Value2 : 1,

caleculatedIt: function(){
    setTimeout(function(){
      console.log(this.Value1 * this.Value2);
    }, 1000);
  }
}

myObj.caleculatedIt(); //4000

为了避免对全局作用域的污染, 所以一般情况下我们尽可能少的声明全局变量。  
变量提升(Variable Hoisting)
所以的变量声明都会提升到函数的开头(如果这个变量在这个函数里面)或者全局作用域的开头(如果这个变量是一个全局变量)。我们来看一个例子:

复制代码代码如下:
function showName () {
console.log ("First Name: " + name);
var name = "Ford";
console.log ("Last Name: " + name);
}

showName (); 
// First Name: undefined
// Last Name: Ford

// The reason undefined prints first is because the local variable name was hoisted to the top of the function
// Which means it is this local variable that get calls the first time.
// This is how the code is actually processed by the JavaScript engine:

function showName () { // www.jbxue.com
    var name; // name is hoisted (note that is undefined at this point, since the assignment happens below)
console.log ("First Name: " + name); // First Name: undefined

name = "Ford"; // name is assigned a value

// now name is Ford
console.log ("Last Name: " + name); // Last Name: Ford
}

函数声明会覆盖变量声明
如果存在函数声明和变量声明(注意:仅仅是声明,还没有被赋值),而且变量名跟函数名是相同的,那么,它们都会被提示到外部作用域的开头,但是,函数的优先级更高,所以变量的值会被函数覆盖掉。

复制代码代码如下:
// Both the variable and the function are named myName
var myName;?
function myName () {
console.log ("Rich");
}

// The function declaration overrides the variable name
console.log(typeof myName); // function

但是,如果这个变量或者函数其中是赋值了的,那么另外一个将无法覆盖它:

复制代码代码如下:
// But in this example, the variable assignment overrides the function declaration
var myName = "Richard"; // This is the variable assignment (initialization) that overrides the function declaration.

function myName () {
console.log ("Rich");
}

console.log(typeof myName); // string

最后一点, 在严格模式下,如果没有先声明变量就给变量赋值将会报错!

javascript中的变量作用域以及变量提升详细介绍的更多相关文章

  1. javascript中的变量作用域以及变量提升

    在javascript中, 理解变量的作用域以及变量提升是非常有必要的.这个看起来是否很简单,但其实并不是你想的那样,还要一些重要的细节你需要理解. 变量作用域 “一个变量的作用域表示这个变量存在的上 ...

  2. 【转载】【翻译】JavaScript Scoping and Hoisting--JS作用域和变量提升的探讨

    原文链接:http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting 你知道下面的JavaScript代码执行后会aler ...

  3. JavaScript中var和this定义变量的区别

    JavaScript中var和this定义变量的区别 在js中声明变量时可以使用var和this,但使用this的有很大一部分参考书是没有的,经过查阅相关资料总结如下: 用var和this声明变量,存 ...

  4. Javascript中闭包的作用域链

    作用域定义了在当前上下文中能够被访问到的成员,在Javascript中分为全局作用域和函数作用域,通过函数嵌套可以实现嵌套作用域. 闭包一般发生在嵌套作用域中.闭包是JavaScript最强大的特性之 ...

  5. Python 再谈变量作用域与变量引用

    再谈变量作用域与变量引用 by:授客 QQ:1033553122 module3.py #!/usr/bin/env python # -*- coding:utf-8 -*-   __author_ ...

  6. javascript中的this作用域详解

    javascript中的this作用域详解 Javascript中this的指向一直是困扰我很久的问题,在使用中出错的机率也非常大.在面向对象语言中,它代表了当前对象的一个引用,而在js中却经常让我觉 ...

  7. 解读JavaScript中的Hoisting机制(js变量声明提升机制)

    hoisting机制:javascript的变量声明具有hoisting机制,JavaScript引擎在执行的时候,会把所有变量的声明都提升到当前作用域的最前面. 知识点一:javascript是没有 ...

  8. JavaScript 变量作用域和声明提升

    一.变量作用域 说到这个概念,不有自主的想到this,scope 这两个关键字. JavaScript的this总是指向一个明确的对象,这个对象是在执行的时候动态绑定的.通俗的说就是谁调用我,我的th ...

  9. JavaScript中是如何定义私有变量的

    前言 JavaScript并不像别的语言,能使用关键字来声明私有变量. 我了解的JavaScript能用来声明私有变量的方式有两种,一种是使用闭包,一种是使用WeakMap. 闭包 闭包的描述有很多种 ...

随机推荐

  1. android124 zhihuibeijing 新闻中心-组图

    package com.itheima.zhbj52.base.menudetail; import java.util.ArrayList; import android.app.Activity; ...

  2. PAT 1017

    1017. Queueing at Bank (25) Suppose a bank has K windows open for service. There is a yellow line in ...

  3. C#_MVC_ajax for form

    在上一篇介绍MVC中的Ajax实现方法的时候,曾经提到了除了使用Ajax HTML Helper方式来实现之外,Jquery也是实现Ajax的另外一种方案. 通过get方法实现AJax请求 View ...

  4. com.ulitis.www

    package com.ulitis.www; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io ...

  5. 优化sql,返回行数少情况下,NL比hash快好多

    sql如下 select t.id, t.value, tt.sort as sortno from ENGINEERING_TYPE t left join ENGINEERING_TYPE tt ...

  6. Java基础知识强化之网络编程笔记12:TCP之TCP协议上传文本文件并给出反馈

    1. 客户端: package cn.itcast_12; import java.io.BufferedReader; import java.io.BufferedWriter; import j ...

  7. arcgis 绝对、相对、UNC 和 URL

    您每天都通过路径浏览至数据和工具箱.在共享数据和工具之前,您对此可能没有做太多考虑,其实您也无需考虑.本部分将详细讨论以下方面内容:路径.定义不同类型的路径以及 ArcGIS 对路径的管理方式. 路径 ...

  8. UVa 1645 Count(**)

    题目大意:输入n,统计有多少个n个结点的有根树,使得每个深度中所有结点的子结点数相同.结果模1000000007. 思路:根据题意,每个结点的每个子树都是相同的.所以n结果为n-1的所有约数的结果加起 ...

  9. 配置Linux数据转发(给其他接口转发一个接口的internet网络)

    配置Linux数据转发 [主机]第一步开启转发net.ipv4.ip_forward = 1echo "1" > /proc/sys/net/ipv4/ip_forward第 ...

  10. (原创)openvswitch实验连载2-cisco模拟器IOU-Web安装及网络环境配置

    IOU的使用可以选择自己到官网https://docs.google.com/file/d/0B2AgRhS2cfxCQ01tN2NrQ0pvNUk/edit下载iou-web 软件,然后部署在lin ...