二、深入之声明前置

0x00、引言

为了对JavaScript的作用域和作用域链有一个更好的理解,我们就需要了解JS这门语言的一个机制,即声明前置。

0x01、从变量的声明前置说起

我比较喜欢从一些小的demo来说起和加深自己对JavaScript这门语言机制的理解,那么声明前置这个也不另外

  • demo1
    console.log(a)      // undefined
    var a = 1
    console.log(a)     //1
    

第二个console.log(a) 打印出1我们好理解,那么上面为什么第一个console会打印出undefined?
这里就不得不提一直说的声明前置,其实var a = 1可以拆解为var aa = 1这样两个部分了,var a是对变量a的声明,a = 1是对变量a的赋值,所谓声明前置就JS引擎在解析这段代码的时候,会将var a声明放置在最前面,即可以改写为以下代码

  • demo1改写

var a //变量a声明前置了
console.log(a) // undefined
a = 1
console.log(a) //1

下面我们再来看一个例子
- demo2
 

console.log(a) // undefined
if (false){
var a
}


这里我们将var a放置在if 语句中,还会声明被前置么,结果是当然,因为在[深入之作用域](http://www.jianshu.com/p/636c5eb548e2)中我们以及知道在JS这门语言中只有全局作用域和函数作用域,无块级作用域(ES6有新增),**因而var a 即使在if/for里面,也会被前置的**


##### 0x02、关于函数的声明前置
我们知道函数有多种的调用方式,但我们这里主要讨论函数的声明前置,所以当用到函数的调用就以最简单的一种函数调用模式为例
- demo3 

fn(2,3); //5
function fn(a,b) {
return a+b;
var c = 1
}

在这个简单的函数调用中,在JS中将定义的函数进行一个声明前置,确保它在被调用前以及被定义了,下面我们可以改写为以下形式
- demo3改写

function fn(a,b) { //全局作用域下定义的函数fn声明前置
var c //函数作用域内声明变量c前置
return a+b;
c = 1
}
fn(2,3); //5

#### 0x03、下面举出几个复杂一点的例子
> 1.若不报错,下面代码输出什么?

var y = 10;

if (!(x in window)) {
    var x = 10;
} else {
    ++y;
}

alert(x);        //undefined,var a 即使在if/for里面,也会被前置的,
                 //但a=10的赋值还会停留在if(){...}中
alert(y);            //11
> 2.重复声明两个函数会怎样?

var m= 1, j = k = 0;
function add(n) {
return n = n+1;
  }
y = add(m); //4,由声明前置我们可以知道后一个函数将在y调用前声明并覆盖掉前一个函数的声明(同名)
function add(n) {
return n = n + 3;
}
z = add(m); //4,z和y的指针其实指向的其实是同一个函数

> 3.对下面进行声明前置的改写

a = 2
b()

var a

function c(){
console.log(a)
}
function b(){
a = 1
c()
var a
}
/------改写------/
var a //全局作用域内的变量a提升
function c(){ //声明函数的变量提升
console.log(a) //重点 ,此时的a指的是全局变量的a
}
function b(){ //声明函数的变量提升
var a //函数作用域内的变量a提升
a = 1
c() //c()函数被调用
}
a = 2
b() //2

你可能感兴趣的:(二、深入之声明前置)