做用域:编程语言最基本的功能就是存储和访问变量的值,如何对变量存储/访问的某种良好的规则,就是做用域。做用域负责收集并维护由全部声明的标示符(变量)组成的一系列查询,并实施一套很是严格的规则,肯定当前执行的代码对这些标识符的访问权限。es6
做用域是根据名称查找变量的一套规则。当一个块或者函数嵌套在另一个块或者函数中时,就发生了做用域嵌套。编程
词法做用域:定义在词法阶段的做用域。词法做用域是你在写代码时将变量和块做用域写在哪里来决定的,所以词法分析器处理代码时保持做用域不变。bash
函数做用域:每声明一个函数都会为自身建立一个做用域,属于这个函数的所有变量均可以在这个函数范围内使用/复用。一段代码咱们能够在它的外部添加一个包装函数,这样就能够将内部的变量和函数定义隐藏(这种方法能够有效解决变量或者函数污染外部做用域,闭包和函数自调用也是这种方法的延伸)。外部做用域没法访问包装函数内部的任何内容。闭包
es5及以前只有函数做用域和全局做用域同时也只有两种变量声明,var 和function。 使用函数及变量的声明都将被提高到当前做用域的最顶部。编程语言
1.变量提高(var的起做用,只有声明提高,初始化不会):
var a =3;
function b( ) {
//实际上var了的变量提高到了函数内部的顶部
console.log( a );
var a=4;
}
b( ); // undefind
实际执行
var a =3;
function b( ) {
var a ; //var a 声明!提高到此,并值为undefined
console.log( a );
a=4; // 初始化
}
b();
2.函数提高(函数声明起做用):
函数提高是把整个函数都提到前面去。
function f( ) {
console.log('I am outside!');
}
( function ( ) {
if ( false ) {
// 重复声明一次函数f
function f( ) {
console.log( 'I am inside!' );
}
}
f( );
}( ) );//输出'I am inside!'
实际执行:
function f( ) { console.log( 'I am outside!' ); }
( function ( ) {
function f( ) { console.log( 'I am inside!' ); }
if ( false ) {
// 重复声明一次函数f
}
f( );
}( ) );
3.全局做用域的会被后面提高上来的覆盖( var的变量为undefined ), 局部做用域的会提高到函数内部的顶部;变量只有var的会提高,函数只有函数声明会提高;
4:函数声明和函数表达式
function a( ){ } //函数声明 会提高
因此 :
a( );
function a ( ){ } //正确
var b = function ( ) { } //函数表达式 不会提高
因此:
b( );
var b = function ( ) { } //错误
复制代码
es6引入了块级做用域,并新增了四种声明let/const/import/class。ide
1.// 只在当前做用域内能够访问
{
let a = 10;
var b = 1;
}
b // 1
a // ReferenceError: a is not defined.
2.// 同一做用域里不容许重复声明
let a = 'aaa';
let a = 'bbb'; //报错 :语法错误
let a = 'aaa';
{let a = 'bbb';} // 不会报错
3.// 不会变量提高
console.log(a); // 报错
let a;
4.//暂时性死区 TDZ
var a =1;
{
let a = 3;
}
// 报错 :引用错误
5.//全局声明不会赋值到window对象
window.d = 123
let d = 234
console.log(d); // 234
2.let/const/import/class也遵照上述规则。
3.const是常量,不可再次被赋值(只限于栈内存里数据,栈内存放的基本数据类型和引用类型的地址不可变)
复制代码
1.let
for(let i =0; i<10; i++){
let i = 123;
setTimeout(
()=>{console.log(i);},
1000);
}
// 30786
// 123
console.log(i) // ReferenceError: i is not defined
for(var i =0; i<10; i++){
setTimeout(
()=> {console.log(i);},
1000);
}
// 51
// 10
for(let i =0; i<10; i++){
setTimeout(
()=> {console.log(i);},
1000);
}
// 0 1 2 3 4 5 6 7 8 9
2.const
const 在for循环中循环一次后会报错,由于i++会修改值;
在for in 和for of中则能够正常使用,由于每次循环会建立一个常量。
// 51
// 10
复制代码