let声明的变量具有块级作用域,for循环流程控制部分(小括号内),循环体部分(大括号内)、以及函数体、大括号包裹的代码块、中使用let声明的变量仅在该块状作用域内可见.如果在全局环境中使用let声明则是全局变量.
在chrome控制台使用let声明变量虽然在当前控制台属于全局变量,但是并不会添加到window对象上
for循环流程控制部分(小括号内)使用let声明的变量循环体内也可见.并且每次循环都会声明一个新的循环变量,js引擎会'记住'上次循环变量的值,并为新声明的循环变量赋值.看下面的代码
let logfuns=[];
let addfuns=[];
for(let i=0;i<10;i++){
logfuns[i]=function(){
console.log(i);
}
addfuns[i]=function(){
i++;
}
}
logfuns[8]();//输出8
addfuns[8]();//此时i的值变为9
logfuns[8]();//输出9
console.log(i);//报错 ReferenceError: i is not defined
由于for中用let声明的变量i,那么每次循环时都会新声明一个同名变量i(同名但不同),由于logfuns和addfuns是全局变量,且对循环中声明的变量i有引用,所以循环结束后i并没有释放,但是由于作用域限制外部无法直接访问变量i,但是函数可以访问到(这里就是js的闭包,可以理解成java的private修饰的变量用get/set访问)
const和let一样具有块级作用域,不过const修饰的变量无法修改变量的值,而且必须声明时同时赋值,无法先声明然后再赋值.
const j=10;
const i;//会报错
i=100;
var声明的变量具有函数级作用域,且有声明提前(let/const没有)
var在函数内的任意位置声明,声明前的代码依然可以访问该变量,就相当于把声明提到了函数的开头.在赋值前此值都是undefined.
在chrome控用var声明变量会添加到window对象上
无论在任何位置,如果不就修饰符声明一个变量,则该变量为全局变量.
js闭包可以实现外部访问内部变量或函数.此时的内部声明的变量依然在内存中没有释放,但是外部无法直接访问,需要通过内部函数来间接访问.
注意大量使用闭包可能导致内存占用高
上面的for循环就是一个例子,接下来再来看下面的例子,思考一下输出结果
let name="张三";
let person={
name:"李四",
age:"18",
sayHello:function(){
console.log("hello "+this.name);
},
sayHi:function(){
return function(){
console.log("hi "+this.name);
}
},
sayNihao:function(){
let that=this;
return function(){
console.log("ni hao "+that.name);
}
}
}
person.sayHello();
person.sayHi()();
person.sayNihao()();
sayHello输出'hello 李四' 这个主要看的是this指向,this指向调用者,这里是person
sayHi输出"hi undefined" 首先person.sayHi()会返回一个函数对象,这个函数对象再执行,返回函数并没有指定调用者,这时会使用全局环境.this会指向window(浏览器环境),但是由于name是let修饰,所以window.name并不存在.如果改成var修饰这里的输出结果为"hi 张三"
sanNihao输出结果为'ni hao 李四',这里是一个闭包,在外部访问内部变量that,根据上面同样的分析that指向person对象