函数提升优先级比变量提升要高,且不会被变量声明覆盖,但是会被变量赋值覆盖。
例题一:
// 变量、函数声明提前
function Foo() {
getName = function () { alert(1); }; //函数内部没有声明getName,往外找
return this;
}
Foo.getName = function () { alert(2); };
Foo.prototype.getName = function () { alert(3); };
var getName = function () { alert(4); };
function getName() { alert(5); }
//请写出以下输出结果:
Foo.getName();
getName();
Foo().getName();
getName();
//2、4、1、1
//首先定义了一个叫Foo的函数,之后为Foo创建了一个叫getName的静态属性存储了一个匿名函数,之后为Foo的原型对象新创建了一个叫getName的匿名函数。
//之后又通过函数变量表达式创建了一个getName的函数,最后再声明一个叫getName函数。
// 第一问
// 第一问的 Foo.getName 自然是访问Foo函数上存储的静态属性,自然是2。
//第二问
// 第二问,直接调用 getName 函数。既然是直接调用那么就是访问当前上文作用域内的叫getName的函数
// 由于变量提升
// function Foo() {
// getName = function () { alert(1); };
// return this;
// }
// var getName;//只提升变量声明
// function getName() { alert(5); }//提升函数声明,覆盖var的声明
// Foo.getName = function () { alert(2); };
// Foo.prototype.getName = function () { alert(3); };
// getName = function () { alert(4); };//最终的赋值再次覆盖function getName声明
// getName();//最终输出4
//第三问
//先执行了Foo函数,然后调用Foo函数的返回值对象的getName属性函数。Foo函数的返回值是this,此处的直接调用方式,this指向window对象,遂Foo函数返回的是window对象,相当于执行 window.getName() ,
//而window中的getName已经被修改为alert(1),所以最终会输出1
//第四问
//直接调用getName函数,相当于 window.getName() ,因为这个变量已经被Foo函数执行时修改了,遂结果与第三问相同,为1
例题二:
如果将test()函数中console.log(foo());语句注释掉,foo()不会被执行。整个输出为undefined
function test(){
console.log(a);
console.log(foo());
var a = 1;
function foo(){
return 2;
}
}
test();
// test()执行顺序:
// 声明提前
//function foo(){return 2;}
// var a;
// 执行console.log(a);由于此时变量只是声明,未赋值,输出undefined
// 执行console.log(foo());此时foo()被执行,输出2
// a = 1;
例题三:
console.log(foo);
function foo(){
console.log('function foo');
}
var foo = 20;
console.log(foo); //20
// 以上代码执行顺序:
// 首先函数声明提升
// function foo(){console.log('function foo');}
// 接着变量声明提升
// var foo = undefined;但因为foo已经存在同名函数,此时以函数值为准,不会被undefined覆盖。
// 最后开始执行阶段代码的执行
// console.log(foo); //function foo()
// foo = 20;
例题四:
使用函数表达式创建的函数,只有变量名会被提前声明。
function test(){
console.log(foo);
console.log(bar);
var foo = 'hello';
console.log(foo);
var bar = function(){
return 'world';
}
function foo(){
return 'hello';
}
}
test();
// 执行顺序
// function foo(){return 'hello';}
// var foo;
// var bar; //只提升了变量声明
// console.log(foo); //function foo()
// console.log(bar); //undefined
// foo = 'hello';
// console.log(foo); //hello
// bar = function(){return 'world';}
注意:
ES6中,新增的let/const,其定义的变量,也会被提前声明,但不会给赋值undefined,所以即使提升了,未赋值前也不能使用。