JavaScript学习系列2一JavaScript中的变量作用域

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

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 = [11,12,13];
function myShow(){

 if(typeof testList === 'undefined')
 {
      testList = [];
 }

alert(testList.length);

};

myShow();//结果 3

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

再看下面

var testList = [11,12,13];
function myShow(){

 if(typeof testList === 'undefined')
 {
     var testList = [];
 }

alert(testList.length);

};

myShow(); //结果 0

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

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

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

var testList = [11,12,13];
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 = 24; //这里有错吗,这里不会报错,为什么呢?  
               //  JavaScript中给一个未定义的变量赋值,就会自动创建一个全局变量, 这就
                   相当于 var age = 24

 

原文地址:https://www.cnblogs.com/wphl-27/p/9327062.html