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

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

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

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

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

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

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

  1. var a;
  2. console.log(a);

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

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

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

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

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

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

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

正常

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

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

  1. var a = function(){
  2.   console.log(52);
  3. }
  4. a(); //

正常

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

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

  1. var a;
  2. if(false){
  3. a = 1;
  4. }
  5. console.log(a);

总结:

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

  函数声明--

  1. function a(){
  2. alert("追梦子博客");
  3. }

  函数表达式--

  1. var a = function(){
  2. alert("追梦子");
  3. }

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

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

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

  

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

为什么打印的是undefined?

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

  1. var a = 1;
  2. function b(){
  3. var a
  4. console.log(a); //undefined
  5. a = 5;
  6. }
  7. b();

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

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

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

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

  

  1. var a = 1;
  2. function b() {
  3. a = 120;
  4. return;
  5. function a() {}
  6. }
  7. b();
  8. alert(a); //1;

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

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

  

  1. var a = 1;
  2. function b() {
  3. var a;
  4. a = 120;
  5. return;
  6. function a() {}
  7. }
  8. b();
  9. alert(a);

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

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

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

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

js中的执行上下文,菜鸟入门基础。的更多相关文章

  1. 进阶学习js中的执行上下文

    在js中的执行上下文,菜鸟入门基础 这篇文章中我们简单的讲解了js中的上下文,今天我们就更进一步的讲解js中的执行上下文. 1.当遇到变量名和函数名相同的问题. var a = 10; functio ...

  2. 通俗易懂的来讲讲js的函数执行上下文

    0.开场白 在平时编写JavaScript代码时,我们并不会和执行上下文直接接触,但是想要彻底搞懂JavaScript函数的话,执行上下文是我们绕不过去的一个知识点. 1.执行上下文栈 JavaScr ...

  3. JS进阶之---执行上下文,变量对象,变量提升

    一.结构顺序大体介绍 JavaScript代码的整个执行过程,分为两个阶段,代码编译阶段与代码执行阶段. 编译阶段由编译器完成,将代码翻译成可执行代码,这个阶段作用域规则会确定. 执行阶段由引擎完成, ...

  4. js中的执行环境及作用域

    最近在面试时被问到了对作用域链的理解,感觉当时回答的不是很好,今天就来说说js中的作用域链吧. 首先来说说js中的执行环境,所谓执行环境(有时也称环境)它是JavaScript中最为重要的一个概念.执 ...

  5. JS中的执行环境和作用域

    window 是最大最外围的执行环境,然后每个函数都有自己的执行环境.JS代码是从上到下执行的,单纯的用语言描述可能会有点绕,而且不大直观.我们看着代码来 console.log('global be ...

  6. Promise对象及它在js中的执行顺序

    关于Promise对象的学习及它的执行顺序 学习阮一峰老师的ES6入门后的记录 1.promise的定义 promise是一个对象,通常包裹着一个异步操作,promise对象提供一些接口的方法,返回一 ...

  7. js作用域与执行环境(前端基础系列)

    一.作用域(what?) 官方解释是:"一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域." 单从文字理解比较难懂,举个栗子: ...

  8. 在JS中统计函数执行次数与执行时间

    假如想统计JS中的函数执行次数最多的是哪个,执行时间最长的是哪个,该怎么做呢? 1. 统计函数执行次数 2. 统计函数执行时间 3. 如何控制函数的调用次数 4. 如何控制函数的执行时间 一.统计函数 ...

  9. JS中的执行机制(setTimeout、setInterval、promise、宏任务、微任务)

    1.执行机制 JS 是单线程的,处理 JS 任务(程序)只能一个一个顺序执行,所以 JS 中就把任务分为了同步任务和异步任务.同步的进入主线程先执行,异步的进入Event Table并注册函数,当指定 ...

随机推荐

  1. 详解Bootstrap进度条组件

    在网页中,进度条的效果并不少见,如:平分系统.加载状态等,进度条组件使用了css3的transition和animation属性来完成一些特效,这些特效在IE9及IE9以下版本.Firefox的老版本 ...

  2. Maven Nexus Setup tutorial

    Technorati 标签: maven,nexus 1. download the Nexus from website for free version: 2. Run the Command p ...

  3. Build Slic3r on Windows // 如何在Windows上编译Slic3r

    下载Strawberry Perl 5.22 64bit绿色版,解压缩到某个地方,比如C盘根目录,比如 C:\strawbrry-perl-5.22.2.1-64bit-portable 下载Boos ...

  4. 使用bootstrap和metroui设计的微网站或手机app界面

    今天使用bootstrap和metroui设计了一个metro风格的移动app或者微信微网站的界面 程序的源代码可以从此处获得:https://github.com/mz121star/weixin- ...

  5. eclipse maven 创建总POM 工程

    首先进入到eclipse的workspace,我这里的workspace目录是D:\workspace 1.创建总的POM D:\workspace>mvn archetype:create - ...

  6. python 相关安装和配置

    永久链接: http://michaelzqm.iteye.com/blog/1841966 预览文章: python环境搭建   2013-04-04 博客分类: 综合   一. window环境安 ...

  7. Android ImageView src与backgroud

    在XML中添加ImageView时,有两个可以设置图片的地方,一个是android:src,一个是android:background,这两个的区别: src是图片内容,显示在前面的,backgrou ...

  8. Android studio NDK 编译 "$USE_DEPRECATED_NDK=true" 异常问题解决

    我的项目是https://github.com/leixiaohua1020/simplest_ffmpeg_mobile/tree/master/simplest_ffmpeg_android_st ...

  9. DataInputStream类和RandomAccessFile类的使用方法

    // DataInputStream类实现了DataInput接口,要想从文件中读入二进制数据, // 你需要将DataInputStream与某个字节源相结合,例如FileInputStream / ...

  10. [AX2012]Report data provider调试

    运行使用RDP作为数据源的报表时,RDP类被编译成.NET的服务调用,RDP是X++的代码,它的调试是在MorphX调试器中完成.要在MorphX调试器中调试RDP的X++代码需要以下配置: 添加AO ...