浅谈js中函数作用域和声明提前
JavaScript的函数具有两个主要特性,一是函数是一个对象,二是函数提供作用域支持,今天主要聊聊函数的作用域支持。
简单看两个概念:
具名函数表达式
var add = function add (a) { return a }
这段代码描述了一个函数,称为‘具名函数表达式’。
如果省略函数表达式中的名字,它就是‘匿名函数表达式’,即匿名函数,例如
var add = function (a, b) { return a + b; };
最后看下‘函数声明’
function foo() { // 函数体 }
函数声明只能出现在“程序代码”中,也就是说在别的函数体内或在全局。这个定义不能赋值给变量或属性,同样不能作为函数调用的参数。
//全局作用域
function foo() {}
//本地作用域
function local() { function bar() {} return bar; }
此时的bar就是在local内,也就是在外面时访问不到的,被称之为局部作用域,那既然这样,我们看下面这段代码
var a = 1; function aa(){ console.log(a); }
此时输出的结果是1,很好理解,因为在函数内部访问不到,因此会去外面寻找,直到找到为止
添加一行代码,再看看
var a = 1; function(){ console.log(a); var a =2 ; }
此时输出结果是underfined;很诧异,没有定义之前可以在函数外部访问到,定义了反而访问不了了,实际情况是什么呢,js在函数内部定义的变量会提升至函数体顶部,但仅仅是定义,并未赋值,因此上述代码是这样的
var a = 1; function(){ var a; console.log(a); var a =2 ; }
既然a定义了,但没赋值,所以console之后当然underfined啦。
既然函数声明会提升,那函数表达式会不会呢,看下面这个例子
// 全局函数 function foo() { alert('global foo'); } function bar() { alert('global bar'); } function hoistMe() { console.log(typeof foo); console.log(typeof bar); foo(); bar(); function foo() { alert('local foo'); } var bar = function () { alert('local bar'); }; } hoistMe();
经过上次的代码,这次就比较容易理解了,里面的函数会覆盖外面定义的函数,但是结果都是什么呢
console.log(typeof foo); // "function" console.log(typeof bar); // "undefined" foo(); // "local foo" bar(); // TypeError: bar is not a function
是不是有点诧异呢,仔细想想也很容易明白
刚才说了,函数声明会提前,所以 变量foo和它的定义实现都被提前了,而且函数定义实现和书写顺序无关的,这里故意写在后面也证明了这一点。
但是函数表达式却没有这个技能,所以变量被提前,而定义却没有提前.
谢谢观看