一、题目代码:
var bar=1;
function test(){
console.log(bar);
var bar=2;
console.log(bar);
}
test();
//会输出什么?
答案和解析在下面
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
二、答案:
三、解析:
js寻找变量先是在自己的域找,找不到了再去外层找
所以当
var bar=1;
function test(){
console.log(bar);
}
test();
这种情况会输出1
由于var声明变量会有变量提升的现象,所以题中的情况等价于
var bar=1;
function test(){
var bar;
//虽然题中没有这句,但是用var定义变量会进行变量提升
//会隐式的声明变量,也就相当于是有这个语句了
console.log(bar);
var bar=2;
console.log(bar);
}
test();
所以很容易得出,在第一个console.log执行时,bar是undefined
第二个console.log自然就是输出上一行在这个域中赋值过的bar
值为2
var bar=1;
function test(){
console.log(bar);
var bar=2;
//如果题目中这里用let或const就会报错:
//Cannot access 'bar' before initialization
//let和const不会变量提升,而上一行用了bar,且在这个域找到了bar
//而bar在声明前就被调用了,所以会报错
console.log(bar);
}
test();
同考点题再练(答案在最下面):
function c(){
var b=1;
function a() {
console.log(b);
var b =2;
console.log(b);
}
a();
console.log(b);
}
c();
//答案undefined 2 1
四、总结:
1.由于变量提升bar的赋值可以写于声明之前,而let,const则不行
let和const必须先声明再赋值或者声明同时赋值
a=3;
console.log(a); //3
var a;
b=3;
console.log(b);//Cannot access 'b' before initialization
let b;
let c=3;
console.log(c);//3
2.var可以重复声明,let和const不能重复声明
let n;
let n=1;//Identifier 'n' has already been declared
var p=1;
var p=2;//不会报错
3.优先级:变量>函数>参数>变量提升
function fn(bar){
var bar=2;//****输出结果来自这里
console.log(bar);
function bar(){
return "函数"
}
}
fn(1);
//输出结果为2,说明变量优先级最大
function fn(bar){
console.log(bar);
var bar=1;
function bar(){//****输出结果来自这里
return "函数"
}
}
fn(2);
//输出结果为ƒ bar(){return "函数"},
//说明函数优先级大于参数和变量提升
function demo(bar){
console.log(bar);
var bar=2;
}
demo(1);//****输出结果来自这里
//输出结果为1,说明参数优先级大于变量提升
function fn(bar){
var bar;
console.log(bar);
bar=2;
}
fn(1);//****输出结果来自这里
//结果输出1,说明变量提升相当于这种写法
function fn() {
return "1"
}
console.log(fn()); //结果是3,对于函数来说,后者覆盖前者
//函数声明的位置可以放在执行语句后面
function fn() {
return "2"
}
function fn() {
return "3"
}
var fn=function (){//fn本质上是个变量
return "1"
}
function fn() {//fn本质上是个函数
return "2"
}
console.log(fn()); //结果是1,变量fn优先级大于函数fn
function fn() {
return "2"
}
console.log(fn);//输出2,函数优先级大于变量提升
var fn=function (){
return "1"
}
4.全局变量
因为,在js中,如果某个变量没有var声明,会自动移到上一层作用域中去找这个变量的声明语句,如果找到,就使用,如果没找到,就继续向上寻找,一直查找到全局作用域为止,如果全局中仍然没有这个变量的声明语句,那么自动在全局作用域进行声明,这个就是js中的作用域链,也叫变量提升
全局变量的三种声明方法:
<script>
var a=1;//function外部定义
window.b=2;//window.定义
window.jQuery = window.$ = jQuery;
//比较典型的比如JQuery1.5中最末一句
function fn(){
c=3;//function内部直接给标识符赋值定义
}
</script>
五、知识巩固
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();
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
答案与解析:
function Foo() {
getName=function(){console.log(1);}
//在函数内标识符赋值,所以这个getName是全局变量
return this;//这个this就是指window
}
Foo.getName=function(){console.log(2);}
Foo.prototype.getName=function(){console.log(3);}
//Foo.prototype是window,所以这个getName也是全局变量
var getName=function(){console.log(4)}
//这个getName在函数外声明也是全局变量
function getName(){console.log(5)}
Foo.getName();//2 执行foo对象的getName
getName();//4 变量优先级大于函数,所以是4不是5
Foo().getName(); //1
//因为这里先执行了Foo()相当于执行了
//getName=function(){console.log(1);}
//return this;
//此时getName=function(){console.log(1);}就覆盖了之前所有的全局变量getName
//而Foo() return的是window,所以这里输出的就是最新的window.getName()
//也就是输出1
getName();//1 执行全局变量getName
new Foo().getName();//3 Foo原型中的getName