JavaScript作用域
- 作用域和变量
- 块级作用域
- 作用域链
- 声明提升
作用域和变量
1、JavaScript作用域:就是代码名字(变量)在某个范围内起作用和效果,目的是为了提高程序的可靠性,更重要的是减少命名冲突。
2、js的作用域分类(es6):全局作用域和局部作用域
- 全局作用域:整个script标签
- 局部作用域:函数作用域
var a = "apple";
console.log(a); //apple
var a = "apple"; //全局
function fighting() {
var a = 'angel'; //局部
}
console.log(a); // apple
块级作用域
var a='apple';
if(true){
var a = 'angel';
}
console.log(a); //'angel'
这其实是一个坑,虽然 if 语句执行完毕后会销毁,但是在js中 if 内内部定义的变量就会变成当前执行环境的变量,这里在最外围,也就是全部变量了,ES6开始定义块级作用域了,这里不过多赘述;除了 if代码块,常见的还有 for循环、while循环也是相似的结构,所以不要被括号所迷惑,在括号内定义的变量不一定就是局部作用域。
作用域链
作用域链(就近原则):函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问。
var a = 'apple';
var b = 'boy';
function fighting() {
var a = 'angel';
console.log(a); //angel
console.log(b) //boy
}
fighting();
console.log(a); //apple
作用域表示区域,作用域链表示次序1… 2… 3… ;在JavaScript中首先会查看函数作用域内部有没有这个变量,再看外围有没有这个变量,这里我们看不见的作用域链帮我们安排好了顺序,规定好了从里到外的顺序,那么函数里面有定义这个变量 a,则第一个 a 的值就是angel;再来看 b,发现函数内部没有 b,然后就去找外围的b,也就是全局的变量 b,找到了,输出 b 是 boy;再看最后一个 a,因为是在全局范围内,只能访问全局变量 a,不能访问局部变量 a,因此返回apple。
我们可以把作用域链想象为铺地砖,铺地砖一般都是从里到外,从里到外铺地砖可以防止把地砖弄脏,从外到里每次铺地砖都要经过外面这层才能抵达。
声明提升
JavaScript代码是由浏览器中的JavaScript解析器来执行的,JS解析器在运行代码的时候分为两步:预解析和代码执行。
- 预解析:js引擎会把js里面所有的 var 还有 function 提升到当前作用域的在前面
- 代码执行:按照代码书写顺序从上外下
var a = 'apple';
function fighting() {
console.log(a); //undefined
var a = 'angel'; //局部变量
console.log(a); //angel
}
fighting();
// 在代码执行之前上面的代码会自动把顺序变成下面的
var a = 'apple';
function fighting(){
var a; //声明提升了
console.log(a);
a = 'angel';
console.log(a)
}
fighting();
函数里面的函数也会被提升上去,提升会比变量更优先
var a = 'apple';
function fighting() {
console.log(a); //undefined
var a = 'angel';
console.log(ss());
function ss(){ // angel //函数里面的函数也会被提升上去,提升会比变量更优先
return a;
}
}
fighting();
// 上面的代码在执行前会按下面这个顺序
var a = 'apple';
function fighting(){
function ss(){
return a;
}
var a;
console.log(a);
a = 'angel';
console.log(ss());
}
fighting();
最后,用一个综合一点的例子:
var b = 'boy';
console.log(b); //boy
function fighting(){
console.log(a); //undefined
console.log(c); //undefined
if(a === 'apple'){a = 'Alice'}
else{a = 'Ada'}
console.log(a); //Ada
var a = 'Andy';
midlle();
function midlle(){
console.log(c++); //undefined
var c = 100;
console.log(++c); //101
small();
function small() {console.log(a);} //Andy
}
var c = a = 88;
function bottom(){
console.log(this.b); //此时this指向全局变量boy
b = 'baby'; //如果在函数里面声明变量前没有var的话,他就是一个全局变量;一般不建议使用
console.log(b); //baby
}
bottom();
}
fighting();
console.log(b); //baby
over!!!