在写这篇文章之前,再次提醒一下

JavaScript 是大小写敏感的语言

// 'test', 'Test', 'TeSt' , 'TEST' 是4个不同的变量名

JavaScript中的变量,最重要的就是它的作用域, JS中变量的作用域其实就是函数作用域

比如我们的浏览器,在JavaScript中,它就是一个被实例化的window对象, 如果我们在window下面定义一个name字段, 那么name字段就具有window这个函数的作用域, 也就是说在整个window下面是可以访问这个name字段来获取它的值的

那现在我们在window下面定义一个函数Function MyFunc, 然后在这个函数里面定义了一个变量myName, 那么这个新定义的变量myName,它的作用域就是在函数MyFunc里面,也就是说只能在MyFunc函数中才可以访问myName变量

上面是在Chrome=》F12的Console中的一个例子. 刚写的时候一直报错,后来发现是我把function写成了Function,第一个字母大写了,就报错

现在我们换一种方式来写,看看会出现什么情况

这里,我们做了一下更改,在函数MyFunc中,在定义name变量之前,就使用console.log(name)语句来输出name, 如果没有在Chrome的console中执行的话,我可能会误以为它应该输出windowName. 因为这个时候,在函数MyFunc中还没定义name, 而全局变量(window对象下的变量)中已经定义了一个name="windowName", 所以我觉得它应该获取全局变量的值。但实际呢,我们可以看到,在实际中它输出的是undefined, 这是怎么个情况呢?

原来JavaScript的解析器在执行函数MyFunc的时候,第一件事情就是寻找这个函数中的所有局部变量,然后再执行后续语句, 所以它会先找到在函数MyFunc中定义了局部变量name, 但既然找到定义了局部变量name,为什么没有取到它的值funcName呢。 而是输出undefined呢。 这是因为解析器虽然先会寻找函数中的所有局部变量,但是在执行语句时,还是一条一条来执行的,所以解析器先找到函数MyFunc中已经定义了局部变量name,然后执行时,一条一条语句来执行

执行第一条语句 console.log(name);  => 此时,发现MyFunc函数中已经定义了局部变量name,但是此时还没有给它赋值,所以得到的就是undefined.

这一点也可以如下解释 JavaScript在解析代码的时候,都会搜索一下var声明的变量,然后将其声明提前。 javascript这个特性被非正式地称为 声明提升(hoisting)

所以,如下语句

alert(name);  // 这里弹出undefined
var name = "Luke";

它实际的解析过程如下:

var name;
alert(name); // 这里弹出undefined
name = "Luke";

那么,我们在换一种写法,来看看

在这里,我们首先定义了一个全局变量name="windowName", 然后在函数中,有一行语句

name="funcName"

注意,这里不是var name = "funcName", 也就是说它并不是在函数MyFunc中定义一个新的变量var name, 而是重新给全局变量name赋值,把它的值由windowName改为了funcName

所以JavaScript解析器在执行MyFunc函数这段代码时,先会去找这个函数内部的局部变量,发现没有。所以执行console.log(name);语句时,获取的就只能是全局变量name的值,这里就是windowName

接下来name="funcName", 将这个全局变量name的值由windowName改为了(重新赋值)funcName, 所以在MyFunc()之后执行console.log(name),输出的是全局变量name中的新值 funcName

我们再来看两个相似的例子

var testList = [,,];
function myShow(){ if(typeof testList === 'undefined')
{
testList = [];
} alert(testList.length); }; myShow();//结果 3

这里结果将输出3,因为在这个例子中,在函数myShow中没有定义testList(var testList), 所以JavaScript编译器找的就是全局变量testList,显然,它的length就是3

再看下面

var testList = [,,];
function myShow(){ if(typeof testList === 'undefined')
{
var testList = [];
} alert(testList.length); }; myShow(); //结果 0

注意到在函数myShow中,var testList是在myShow函数内部的if语句块中定义的。 这里要注意一下

JavaScript中没有块级作用域(由{}限定的作用域), 函数中声明的变量,无论在函数内部的哪一个地方声明,在这整个的函数中都是有定义的,都是一样的效果。

所以,这里,实际的执行过程是这样的:

var testList = [,,];
function myShow()
{
var testList; if(typeof testList === 'undefined')
{
testList = [];
} alert(testList.length); }; myShow(); //结果 0

所以在执行函数myShow时,发现定义了和全局变量testList同名的局部变量,此时还没给它赋值,所以确实是undefined, 所以执行if条件中的语句, testList = [], 它的length就是0

接下来,我们来看看函数定义式函数表达式之间的区别

函数定义式  function show(){} 采用这种函数定义式的声明方法,函数的定义会提前

函数表达式 var show = function(){}  函数的表达式,和普通的JavaScript变量的处理是一样的,也就是说函数声明会提前,但函数定义的位置不变

我们来看下面两个例子

alert(typeof myFunc);  //输出结果: function
function myFunc(){}

JavaScript在解析代码时, 像function myFunc()这种函数定义,和var声明定义变量一样,都会被提到前面。不同点在于:

var声明定义变量时,只会把var声明提到最前面,而定义还会停留在原处

而函数定义function myFunc(),函数声明和定义是一起的,都会同时被提到前面。所以上面的语句和下面执行是一样的

function myFunc(){}
alert(typeof myFunc); //输出结果: function

那我们再来看函数表达式的例子

alert(typeof myFunc); //输出: undefined
var myFunc = function(){};

这个执行起来就是下面这样的

var myFunc;
alert(typeof myFunc); //输出: undefined
myFunc = function(){};

我们再来看两个更容易出错更让人抓狂的例子

var myData = {name:'testName'};
function myData()
{
alert('testName function');
}
myData(); //输出 TypeError: object is not a function

这个例子非常抓狂吧,这里很容易以为是输出"testName function". 这个确实是很难辨别的一个例子

我们前面说过,var声明定义的变量会把声明提前,通过function myFunc(){}这种函数定义的函数会把函数的声明和定义同时提前. 这里就是这种情况,两个都会提前,那到底谁更前呢? 注意

var声明定义变量和函数定义同名时,函数的声明定义会在更前面,所以上面的JavaScript执行时会变成如下:

function myData()
{
alert('testName function');
}
var myData;
myData = {name:'testName'}; myData(); //输出 TypeError: object is not a function

可以看出,myData此时不再是函数,所以你不能采用这种方法myData(), 所以报错

那我们再看下面这个例子

var myData = {name:'testName'};
var myData = function()
{
alert('testName function');
}
myData(); //输出结果: testName function

在这里函数是通过函数表达式(而不是函数定义式)的var形式来声明定义的,而前面的变量var myData = {name:'testName'}也是var形式,两个优先级是一样的,所以就按代码顺序来,实际执行过程如下

var myData;
myData = {name:'testName'};
myData = function()
{
alert('testName function');
}
myData(); //输出结果: testName function

上面的例子就是这样,JavaScript的变量是一个非常绕的事情, 我们再来看一个例子

alert(name);  //报错: 对象未定义, 使用一个压根就不存在的变量,所以出错

age = ; //这里有错吗,这里不会报错,为什么呢?
// JavaScript中给一个未定义的变量赋值,就会自动创建一个全局变量, 这就
相当于 var age =

JavaScript学习系列2一JavaScript中的变量作用域的更多相关文章

  1. JavaScript学习系列博客_3_JavaScript中的变量、常量、标识符

    常量:就是改变不了的,也是可以直接使用的. 变量:可以改变的,不确定的. var =123456; 通过 var 声明一个变量,同时赋值给它 标识符:在JS中所有的可以自主命名的内容,都可以认为是一个 ...

  2. JavaScript学习系列博客_4_JavaScript中的数据类型

    JavaScript中有6种数据类型 一.基本数据类型 - String 字符串 JS中的字符串需要使用引号引起来双引号或单引号都行 但是要注意的是某种引号嵌套使用的话,需要加上 \ 转义.比如说我们 ...

  3. JavaScript学习系列博客_5_JavaScript中的强制类型转换

    -强制类型转换为String 1.方式1 调用被转换数据的toString()方法 number类型值.布尔类型值.都可以调用toString()方法强制转换.但是null值和undefined值不行 ...

  4. JavaScript学习系列博客_19_JavaScript中方法(method)

    方法 - 听了不少调用什么什么方法,所以方法究竟是啥东西? - 如果一个函数作为一个对象的属性保存,那么我们称这个函数时这个对象的方法,调用这个函数就说调用对象的方法(method). 创建一个对象 ...

  5. JavaScript学习系列博客_17_JavaScript中的函数的参数、返回值

    数的形参(形式参数) - 定义函数时,可以在()中定义一个或多个形参,形参之间使用英文逗号隔开:定义形参就相当于在函数内声明了对应的变量但是并不赋值,形参会在调用时才赋值. 函数的实参(实际参数) - ...

  6. JavaScript学习系列博客_16_JavaScript中的函数(Function)简介

    函数(Function) - 函数也是一个对象,也具有普通对象的功能 - 函数中可以封装一些代码,在需要的时候可以去调用函数来执行这些代码:当调用函数时,函数中封装的代码会按照顺序执行. - 使用ty ...

  7. JavaScript学习系列博客_14_JavaScript中对象的基本操作

    对象的基本操作 - 创建对象 - 方式一:使用new关键字调用的函数,是构造函数(constructor),构造函数是专门用来创建对象的函数. var obj = new Object(); - 方式 ...

  8. JavaScript学习系列博客_13_JavaScript中的对象(Object)简介

    对象 对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性.除了那5种基本数据类型,就是对象. 分类:1.内建对象- 由ES标准中定义的对象,在任何的ES的实现中都可以使用- 比如:Ma ...

  9. JavaScript学习系列博客_12_JavaScript中的break、continue关键字

    break关键字 -break关键字可以用来退出switch或循环语句 -不能在if语句中使用break和continue,但不是说if语句里面不能写break关键字,break关键字一定要包含在sw ...

随机推荐

  1. server.xml笔记

    本文总结自: http://www.importnew.com/26156.html 核心元素: 顶层元素: server service 连接器: connector 容器: engine > ...

  2. Jquery实现动态导航栏和轮播导航栏

    动态导航栏和轮播导航栏的实现思想: 利用jquery技术的append()方法和bind()方法实现li标签的添加和点击事件绑定,在利用$getJSON(url,data,function)请求方法实 ...

  3. 常用连续型分布介绍及R语言实现

    常用连续型分布介绍及R语言实现 R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大. R语言作为统计学一门语言,一直在小众领域闪耀着光芒.直到大数 ...

  4. HTML-CSS浮动元素详解

    浮动定位是指 1.1将元素排除在普通流之外,即元素将脱离标准文档流 1.2元素将不在页面占用空间 1.3将浮动元素放置在包含框的左边或者右边 1.4浮动元素依旧位于包含框之内 2. 浮动的框可以向左或 ...

  5. L103

    Give everyday the chance to become the most beautiful day of your life.把每天都过成你生命中最美好的一天.competence 能 ...

  6. 树套树Day1线段树套平衡树bzoj3196

    您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查 ...

  7. bzoj 2434: 阿狸的打字机 fail树+离线树状数组

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=2434 题解: 首先我们可以发现这个打字的过程本身就是在Trie上滚来滚去的过程 所以我们 ...

  8. VIJOS:P1706(舞会)

    描述 Arthur公司是一个等级森严的公司,它们有着严格的上司与下属的关系,公司以总裁为最高职位,他有若干个下属,他的下属又有若干个下属,他的下属的下属又有若干个下属……现接近年尾,公司组织团拜活动, ...

  9. HDOJ5044(最近公共祖先)

    #include<cstdio> #include<cstring> using namespace std; ; struct Edge{ int v,id,next; }e ...

  10. 【转】 Pro Android学习笔记(六十):Preferences(4):MultiSelect List Preference

    目录(?)[-] XML文件 在设备中保存 读出信息 ListPreference提供单选列表,我们可以通过CheckBoxPreference提供多选列表.此外,Android在3.0后提供Mult ...