js中的执行上下文,菜鸟入门基础。

console.log(a); //Uncaught ReferenceError: a is not defined

因为没有定义a所以报错了。

var a = 52;
console.log(a); //52

有定义a,并且给a赋值了52所以打印a就是52。

console.log(a); //undefined
var a = 52; 

虽然有定义a但是打印却在变量a的前面,那为什么不是报错而是打印出来的是undefined?因为在js执行代码之前,js会先获取到所有的变量并且把这些变量放置到js代码的顶部。(简称变量声明提前)

实际上,上面的代码是这样执行的:

var a;
console.log(a);

所以代码出来的就是undefined,那你是不是会疑问?我们给赋值给a的52到哪去了。虽然我前面说了js会事先获取所有的变量并且将这些变量放置到顶部,但是变量的赋值并不会事先执行,也就是说,你在哪声明的变量,这个变量的赋值就在哪执行。

var a;
console.log(a); //undefined

虽然声明了但没有赋值所有undefined

console.log(a); 
function a(){
  this.user = "追梦子";
}

为什么,可以事先就打印出函数a呢?因为函数的赋值在函数声明的时候就已经赋值了,结合上面我说的变量提前,那是不是就可以理解这句话了?

当然这只是一种情况,还有一种情况,稍后说。

function a(){
  this.user = "追梦子";
}
console.log(a);

正常

a(); //Uncaught TypeError: a is not a function
var a = function(){
  console.log(52);
}

为什么现在又不行了?因为现在的函数已经赋值给了变量a,现在它的执行过程和变量一样了,我们通常把这种函数赋值给变量的形式叫做函数表达式。

var a = function(){
  console.log(52);
}
a(); //52

正常

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

之所以没有报错而是输出了undefined是因为变量存在预解析的情况,又因为js没有块级作用域,所以最后代码就成了这样

var a;
if(false){
    a = 1;
}
console.log(a);

 

总结:

  函数分为:函数声明和函数表达式。

  函数声明--

function a(){
    alert("追梦子博客");
}

  函数表达式--

var a = function(){
    alert("追梦子");
}

  看似两段相同的语句,它们的执行顺序却截然不同,函数声明时的赋值行为是在函数创建的时候进行的,而函数表达式的赋值行为是在执行这句变量时进行的(因为它已经赋值给了变量所以我这里把它称为变量)。

  不管是变量还是函数都会存在变量声明提前。

来看看几题有意思的js例题,加以理解。

  

var a = 1;
function b(){
    console.log(a); //undefined
    var a = 5;
}
b();

为什么打印的是undefined?

  我们先来看看它的解析过程:

复制代码
var a = 1;
function b(){
    var a
    console.log(a); //undefined
    a = 5;
}
b();
复制代码

  变量提前了,那为什么不打印全局变量1呢?如果你有这个问题我猜你应该是JavaScript的新朋友,那我建议你看我的上一篇文章:

什么是作用域链,什么是原型链,它们的区别,在js中它们具体指什么?

  在看完作用域链以后我相信你能够看懂这个例子。

我们一起来看看另外一题比较有难度的js面试题:

  

复制代码
var a = 1;      
function b() {      
    a = 120;      
    return;      
    function a() {}
}      
b();      
alert(a); //1;
复制代码

  如果你看了上面一题我相信你应该有种不知所措的感觉,这里现在为什么又是1了呢?

我把执行过程的代码写出来我相信你就懂了。

  

复制代码
var a = 1;      
function b() {
    var a;      
    a = 120;      
    return;      
    function a() {}
}      
b();      
alert(a); 
复制代码

  如果你正在js的进阶阶段肯定更闷了,你肯定会想我们不是写return了吗?return后面的代码不是不执行吗?为什么这里却影响了这段代码?

  虽然return后面的代码不会被执行,但是在js预解析的时候(变量提升的时候)还是会把return后面的变量提前,所以我们这段代码因为变量提前所以函数里面的变量a就成了局部变量,因为函数外部是访问不了函数内部的变量所以就输出了1。

  另外提两点,函数的arguments和函数名都是直接赋值的,也就是在这个函数解析的时候就会进行赋值。

  如果你还是不理解建议多看几遍,另外如果你是js的新朋友一定要看什么是作用域链,什么是原型链,它们的区别,在js中它们具体指什么?这篇文章。

 
posted on 2016-02-25 18:08  張暁磊  阅读(135)  评论(0编辑  收藏  举报