变量声明
动态与静态语言
编程语言分为动态(类型)语言和静态(类型)语言,动态类型语言是指在运行期间才去做数据类型检查的语言,也就是说,在用动态类型的语言编程时,永远也不用给任何变量指定数据类型,该语言会在第一次赋值给变量时,在内部将数据类型记录下来。Python、Ruby和JavaScript就是典型的动态类型语言。静态类型语言与动态类型语言刚好相反,它的数据类型是在编译其间检查的,也就是说在写程序时要声明所有变量的数据类型,C/C++是静态类型语言的典型代表,其他的静态类型语言还有C#、Java等。
变量声明提升(hoisting机制)
JavaScript的变量声明具有hoisting机制,JavaScript引擎在执行的时候,会把所有变量的声明都提升到当前作用域的最前面。
以下代码输出v为undefined
var v = "hello";
(function(){
console.log(v);
var v = "world";
})();
以上代码相当于:
var v = "hello";
(function(){
var v;
console.log(v);
v = "world";
})();
由于对变量v的声明被提升到相对于该变量作用域的最前面,所以输出值为undefined。
声明提升
当前作用域内的声明都会被提升到作用域的最前面,包括变量和函数的声明。
(function(){
var a = "1";
var f = function(){};
var b = "2";
var c = "3";
})();
以上代码相当于:
(function(){
var a,f,b,c;
a = "1";
f = function(){};
b = "2";
c = "3";
})();
以上代码请注意函数表达式并没有被提升,这也是函数表达式和函数声明的区别:如果函数被声明了,提升的是函数名,否则提升的是函数表达式。
示例:
(function(){
//var f1,function f2(){}; //hoisting,被隐式提升的声明
f1(); //ReferenceError: f1 is not defined
f2();
var f1 = function(){};
function f2(){}
})();
名字解析顺序:
javascript中一个名字(name)以四种方式进入作用域(scope),其优先级顺序如下:
1、语言内置:所有的作用域中都有 this 和 arguments 关键字
2、形式参数:函数的参数在函数作用域中都是有效的
3、函数声明:形如function foo() {}
4、变量声明:形如var bar;
名字声明的优先级如上所示,也就是说如果一个变量的名字与函数的名字相同,那么函数的名字会覆盖变量的名字,无论其在代码中的顺序如何。但名字的初始化却是按其在代码中书写的顺序进行的,不受以上优先级的影响。看代码:
(function(){
var foo;
console.log(typeof foo); //function
function foo(){}
foo = "foo";
console.log(typeof foo); //string
})();
如果形式参数中有多个同名变量,那么最后一个同名参数会覆盖其他同名参数,即使最后一个同名参数并没有定义。
以上的名字解析优先级存在例外,比如可以覆盖语言内置的名字arguments。
命名函数表达式
可以像函数声明一样为函数表达式指定一个名字,但这并不会使函数表达式成为函数声明。命名函数表达式的名字不会进入名字空间,也不会被提升。
f();//TypeError: f is not a function
foo();//ReferenceError: foo is not defined
var f = function foo(){console.log(typeof foo);};
f();//function
foo();//ReferenceError: foo is not defined
命名函数表达式的名字只在该函数的作用域内部有效。
作用域
https://blog.csdn.net/yueguanghaidao/article/details/9568071