在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
 
// 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 () {
    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. ASP.NET是如何在IIS下工作的

    ASP.NET与IIS是紧密联系的,由于IIS6.0与IIS7.0的工作方式的不同,导致ASP.NET的工作原理也发生了相应的变化. IIS6(IIS7的经典模式)与IIS7的集成模式的不同 IIS6 ...

  2. React在开发中的常用结构以及功能详解

    一.React什么算法,什么虚拟DOM,什么核心内容网上一大堆,请自行google. 但是能把算法说清楚,虚拟DOM说清楚的聊聊无几.对开发又没卵用,还不如来点干货看看咋用. 二.结构如下: impo ...

  3. Android数据加密之MD5加密

    前言: 项目中无论是密码的存储或者说判断文件是否是同一文件,都会用到MD5算法,今天来总结一下MD5加密算法. 什么是MD5加密? MD5英文全称“Message-Digest Algorithm 5 ...

  4. .Net 分布式云平台基础服务建设说明概要

    1)  背景 建设云平台的基础框架,用于支持各类云服务的业务的构建及发展. 2)  基础服务 根据目前对业务的理解和发展方向,总结抽象出以下几个基础服务,如图所示 3)  概要说明 基础服务的发展会根 ...

  5. Boost信号/槽signals2

    信号槽是Qt框架中一个重要的部分,主要用来解耦一组互相协作的类,使用起来非常方便.项目中有同事引入了第三方的信号槽机制,其实Boost本身就有信号/槽,而且Boost的模块相对来说更稳定. signa ...

  6. ReactiveCocoa代码实践之-UI组件的RAC信号操作

    上一节是自己对网络层的一些重构,本节是自己一些代码小实践做出的一些demo程序,基本涵盖大多数UI控件操作. 一.用UISlider实现调色板 假设我们现在做一个demo,上面有一个View用来展示颜 ...

  7. VPN连接常见错误汇总

    提示远程服务器没有响应. 这种情况有两种情况,一种是远程服务器出现故障.另一种是自己的电脑出现问题,具体原因我还没有找到,但是可以肯定的是注册表除了问题,一个终极的解决办法就是把注册表替换了.先将HK ...

  8. ubuntu进行子域名爆破

    好记性不如烂笔头,此处记录一下,ubuntu进行子域名的爆破. 先记录一个在线的子域名爆破网址,无意中发现,很不错的网址,界面很干净,作者也很用心,很感谢. https://phpinfo.me/do ...

  9. 递归实现n(经典的8皇后问题)皇后的问题

    问题描述:八皇后问题是一个以国际象棋为背景的问题:如何能够在8×8的国际象棋棋盘上放置八个皇后, 使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行.纵行或斜线上 ...

  10. 如何让spring mvc web应用启动时就执行特定处理

    Asp.Net的应用中通过根目录下的Global.asax,在Application_Start方法中做一些初始化操作,比如:预先加载缓存项对网站热点数据进行预热,获取一些远程的配置信息等等. Spr ...