概述
首先还是从题目入手吧,很经典,虽然这些题目在网上能找到很多解释方法,不过还是那句话,还是需要自己去理解,这样这个知识点才是你的。
————————————————————————————————————————————————————
if (!("a" in window)) {
var a = 1;
}
alert(a);
答案是undefined
if (!("a" in window)) {
a = 1;
}
alert(a);
答案是1
————————————————————————————————————————————————————
不知道你做对了吗?
由这道题我们可以引出一个知识点-----变量的作用域
还是跟以前一样,首先列出一些“预习”的知识点,供我们后面分析使用:
1.JS中是以函数作为作用域,而我们平时所用的if 或者 for这样的代码块中,是没有作用域的,所以里面的变量对外是可见的。
2.全局变量是指定义在所有函数之外的变量,与之相对应的就是局部变量,它是指定义在某个函数中的变量。
3.函数内的代码可以访问全局变量,反之若函数外的代码去访问函数内的变量则不行。
function a(){
var b=1;
alert("函数内:b="+b);
}
a();
alert("函数外:b="+b);
这个例子就可以佐证第三条知识点,只会打印出函数内的值,函数外的则为未定义)
4.如果我们声明一个变量时没有使用var语句,该变量就会被默认为全局变量。
function a(){
b=1;
alert("函数内:b="+b);
}
a();
alert("函数外:b="+b);
(这个例子正好佐证了第四条知识点)
5.当JS执行过程中进入新的函数时,这个函数内被声明的所有变量都会被移动(提升)到函数最开始的地方,而且只有函数体内声明的变量在该函数执行开始时就存在,但是与之相关的赋值操作并不会被提升,还是在原来的位置上。
function a(){
alert("函数内:b="+b);
var b=1;
}
a();
会alert出undefined
function a(){
alert("函数内:b="+b);
b=1;
}
a();
这个程序就会报错,b未定义
(第1个例子正好佐证了第五条知识点,为什么要写第2个例子呢?就是因为在上一条中我们说未被var的变量我们定义为一个全局变量,那既然是个全局变量的话,我们第三点又说函数内可以访问全局变量,那为什么还是错误的呢?原因在于在该函数被调用之前,这个变量是不存在的,该变量会在它首次被调用的时候创建被赋予全局作用域,而刚才我们在第五点中又说到了只有声明的变量才会被提前,赋值并不会,所以这里会报错)
——————————————————————————————————————————————————
哇,不知不觉都总结出了5个知识点,感觉认真总结完之后,那个题目是不是就迎刃而解了呢?
还是回到我们的题目上来吧
第一个题目中 ("a" in window)的意思是变量a是否是window的属性,即a存不存在,如果是不存在我们就把它赋值1后再打印,存在则直接打印出来。
if (!("a" in window)) {
var a = 1;
}
这里的答案是undefined,是存在的,但是未定义,意思就是没进入这个if里面的语句,利用我们刚才说的知识点,变量声明的时候会被提前,var a=1其实可以被分解为var a; a=1; 而且if是不存在作用域的,所以我们可以把这个代码改写一下。
var a;
if(!("a") in window)) {
a=1'
}
这样是不是就好理解了呢?
然后再来看我们的第二个题目
if (!("a" in window)) {
a = 1;
}
这里答案是1,不用我多说了吧,跟我第5个知识点举的第二个例子差不多,只有当我们去执行a=1这句的时候才会把a给赋予全局变量,所以在此之前a都是不存在的,它就会引入if里面的语句,被赋值于1,并定义为全局变量。
—————————————————————————————————————————————————
当然这里还有一个额外的知识点需要提一下,函数声明和变量声明如果在一起的时候,函数声明提前。
var a=1;
function a() { }
alert(a);
因为上面的例子可以改写成:
function a() { }
var a;
a=1;
alert(a);
但是如果你没赋值的话
var a;
function a() { }
alert(a);
就会打印出函数a
为什么呢?因为a没赋值,所以没覆盖a以前的值(函数),不知道我这样理解对不对呢?
2017/8/9更新:
如何理解作用域和作用域链?
我个人目前的一个理解水平:
作用域我可以理解为数据的有效范围;一个函数就是一个单独的作用域,如果我数据定义在函数里面,那么我这个数据就是局部数据(变量),如果不是则为全局数据(变量);JS中有一个全局作用域和局部作用域的概念,我个人认为是以数据是否定义在函数中区分的。
我们知道函数里面能够使用全局变量,但是函数外面不能够使用局部变量;也就是我们的局部作用域中的数据不能被外部所使用,但是全局作用域中的数据可以被内部所使用;
当我们在函数中去使用某一个变量的时候,发现这个数据不在函数里面,那么就会去它的上一层作用域中去寻找(因为函数可以是进行嵌套的,所以没说全局作用域),发现有这个数据,那么我们就拿来使用;这种结果我个人认为就是作用域链的结果;不过这种链是单向的,毕竟我们也可以想象得到,变量的命名是很容易重复的,如果我们可以反向去搜索,那到底哪一个变量才是我们需要的呢?会造成混乱。
如果再进一步去思考的话就会涉及到“闭包”这个概念:
我们知道当一个函数执行完毕后会自动销毁,那么也就意味着它的作用域也会被销毁,里面的数据也会被销毁;那我们刚才说我们为什么可以在函数中使用到全局变量呢?作用域链是一方面,我们能够找到这个变量,还有就是这个全局作用域一直存在(因为你页面一直打开的话,js进程就会一直在运行,这个作用域就会一直存在),所以也使得我们可以能够使用它;如果我们是函数嵌套呢?也就是说变量的作用域不是全局,而是在它上一层的局部作用域里面呢?
就比如下面这个函数:
function a(){
var name='lzj';
return function b(){
console.log(name);
}
}
我们调用发现a( )( ) 仍然可以访问到name这个变量,说明a( )执行完后name这个变量并没有随之销毁,其实是因为b这个函数中用到了这个变量,导致其一直存在我们的内存中;
这个现象就是我们平时中遇到的“闭包”吧,我们可以利用其保存我们想要的私有变量,不被污染,因为如果我们不这样做,就得实现一个全局变量去保存,这样很容易造成命名空间污染;
2017/8/18更新:
var z=20;
(function(){
var z=10;
function foo(){
console.log(z);
}
foo();
})( ) //10
var z=20;
function foo(){
console.log(z);
}
(function(){
var z=10;
foo(); //20
})()
上面两个例子的结果完全不一样,这里有一点非常重要,就是函数的作用域在其定义的时候,并不是在其使用的时候~
由于第二个例子的作用域在其定义的时候就在外面,并不是在匿名函数里面,所以它的作用域链式指全局变量的,并不是这个匿名函数,所以这里并没有形成我们的“闭包”!
这里非常重要!因为今天面试我就答错了~!!!!!!!!!!!!哎 悲剧
最后
以上就是热情小蘑菇为你收集整理的从面试题分析变量作用域的全部内容,希望文章能够帮你解决从面试题分析变量作用域所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复