You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
functiontest(){foo();// TypeError "foo is not a function"bar();// "this will run!"varfoo=function(){// function expression assigned to local variable 'foo'alert("this won't run!");}functionbar(){// function declaration, given the name 'bar'alert("this will run!");}}test();
引子
首先大家看一下下面的代码,猜猜会输出什么结果?
答案是10!
你是否会疑惑条件语句
if(!foo)
并不会执行,为什么foo
会被赋值为10再来看第二个例子
答案还是10吗?显然不是,
alert
输出了1如果你仍然对上面两个输出结果摸不着头脑,那么请认真阅读这篇文章
Scoping in Javascript
Javascript的作用域已经是老生常谈的问题了,但是不一定每个人都能准确理解。
我们先来看一下C语言的一个例子:
程序依次输出了1,2,1
为什么第三个输出了1而不是2呢?因为在C语言中,我们有块级作用域(block-level scope)。在一个代码块的中变量并不会覆盖掉代码块外面的变量。我们不妨试一下Javascript中的表现
输出的结果为1,2,2
if
代码块中的变量覆盖了全局变量。那是因为JavaScript是一种函数级作用域(function-level scope)所以if中并没有独立维护一个scope,变量x
影响到了全局变量x
C,C++,C#和Java都是块级作用域语言,那么在Javascript中,我们怎么实现一种类似块级作用域的效果呢?答案是闭包
上面代码在if条件块中创建了一个闭包,它是一个立即执行函数,所以相当于我们又创建了一个函数作用域,所以内部的
x
并不会对外部产生影响。Hoisting in Javascript
在Javascript中,变量进入一个作用域可以通过下面四种方式:
function foo() {}
var foo
其中,_在代码运行前,函数声明和变量定义通常会被解释器移动到其所在作用域的最顶部_,如何理解这句话呢?
上面这段在吗,被代码解释器编译完后,将变成下面的形式:
我们注意到,
x
变量的定义被移动到函数的最顶部。然后在bar()
后,再对其进行赋值。再来看一个例子,下面两段代码其实是等价的:
所以变量的上升(Hoisting)只是其定义上升,而变量的赋值并不会上升。
我们都知道,创建一个函数的方法有两种,一种是通过函数声明
function foo(){}
另一种是通过定义一个变量
var foo = function(){}
那这两种在代码执行上有什么区别呢?来看下面的例子:
在这个例子中,
foo()
调用的时候报错了,而bar能够正常调用我们前面说过变量会上升,所以
var foo
首先会上升到函数体顶部,然而此时的foo
为undefined
,所以执行报错。而对于函数bar
, 函数本身也是一种变量,所以也存在变量上升的现象,但是它是上升了整个函数,所以bar()
才能够顺利执行。再回到一开始我们提出的两个例子,能理解其输出原理了吗?
其实就是:
其实就是:
这就是为什么,我们写代码的时候,变量定义总要写在最前面。
ES6有何区别
在ES6中,存在
let
关键字,它声明的变量同样存在块级作用域。而且函数本身的作用域,只存在其所在的块级作用域之内,例如:
上面这段代码在ES5中的输出结果为
I am inside!
因为f被条件语句中的f上升覆盖了。在ES6中的输出是
I am outside!
块级中定义的函数不会影响外部。如果对let的使用,或ES6的其他新特性感兴趣,请自行阅读ES6文档。
The text was updated successfully, but these errors were encountered: