变量声明提升:
JavaScript的函数作用是指在函数内声明的所有变量在函数体内始终是有定义的,也就是说变量在声明之前已经可用,所有这特性称为声明提前(hoisting),即JavaScript函数里的所有声明(只是声明,但不涉及赋值)都被提前到函数体的顶部:
var scope = 'global';
function f(){
console.log(scope);
var scope = 'local';
console.log(scope);
}
由于函数内声明提升,所以上面的代码实际上是这样的:
var scope = 'global';
function f(){
var scope; //变量声明提升到函数顶部
console.log(scope);
scope = 'local'; //变量初始化依然保留在原来的位置
console.log(scope);
}
函数声明提升
1、函数声明语法
f('superman');
function f(name){
console.log(name);
}
// 运行上面的程序,控制台能打印出supemran。
2、函数表达式语法
f('superman');
var f= function(name){
console.log(name);
}
// 运行上面的代码,会报错Uncaught ReferenceError: f is not defined(…),错误信息显示说f没有被定义。
这是因为,函数声明有一个非常重要的特征:函数声明提升,函数声明语句将会被提升到外部脚本或者外部函数作用域的顶部(是不是跟变量提升非常类似)。正是因为这个特征,所以可以把函数声明放在调用它的语句后面。
练习1
var getName = function(){
console.log(2);
}
function getName (){
console.log(1);
}
getName();
上面代码根据变量声明提升和函数声明提升解析如下:
var getName; //变量声明提升
function getName(){ //函数声明提升到顶部
console.log(1);
}
getName = function(){ //变量赋值依然保留在原来的位置
console.log(2);
}
getName(); // 最终输出:2
练习2
function Foo() {
getName = function () { console.log(1); };
return this;
}
Foo.getName = function () { console.log(2);};
Foo.prototype.getName = function () { console.log(3);};
var getName = function () { console.log(4);};
function getName() { console.log(5);}
// 请写出以下输出结果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
上面代码根据变量声明提升和函数声明提升解析如下:
var getName;
function getName() { console.log(5) }
getName = function () { console.log(4) };
function Foo() {
getName = function () { console.log(1); };
return this;
}
Foo.getName = function () { console.log(2);};
Foo.prototype.getName = function () { console.log(3);};
Foo.getName(); // 2
getName(); // 4
Foo().getName(); // 调用了Foo, 输出1
getName(); // 因为调用了Foo,重新给getName赋值, 输出1
new Foo.getName(); // 2
new Foo().getName(); // 3
new new Foo().getName(); // 3