javascript的执行和预解析
很久以前遇到过一个面试题目,的的确确是面试官问我的问题,下面是这个问题的代码部分。由于年少无知,没有回答上,被无情pass了。
var u ='hello world';
;(function(){
alert(u);
var u = 'bonjour la monde';
})();
//请问alert的结果是什么?.
一开始毫不犹豫地想到 alert出来的是hello world; 面试官一脸无奈看着我,耸耸肩,我就大概知道被鄙视了。其实结果是undefined,但是一直没想通这样一个结果。后来才明白,JavaScript解析过程分为两个阶段,一个是预解析阶段,另外一个就是执行阶段。
执行阶段我们应该都很明白是什么意思
var u = 'hello world';
alert(u);
这段代码的结果是在浏览器中弹出出hello world不错,很简单,同样简单的还有下面的代码
alert(u);
var u = 'hello world';
结果是undefinded。因为u是在alert之后初始化的。所以按照从上到下的执行顺序来说,这样的结果是我们能够接受的。那么下面的代码呢?
u();
function u() {
alert('hello world');
}
结果是alert弹出hello world;这是为什么呢?u()明显地是在function函数上面先调用的,为什么函数能够执行呢?
其实在执行代码之前,浏览器会对js代码做预解析,解析的原则是这样的: 对该环境内用var声明变量进行提升到顶部的动作,并给它一个初始值undefined,同样,浏览器也会对function做提升动作,但是值是function返回的值,而不是undefined。并且按照命名唯一的原则,会将后声明的函数覆盖之前声明的同名函数上。如果你对上述说明不是很明白,我们可以换一种说法:浏览器在刷新的时候会悄悄地去执行。界面的js代码,不过它的执行方式是把所有在环境(window 或者 function)内声明的var 变了全部置顶并初始化为undefined。所以我们一开始面试官出题的代码在预解析之后可以等同于以下代码。
var u = 'hello world';
;(function(){}
var u;//或者var u = undefined;
alert(u);
u = 'bonjour la monde';
})();
有两个变量u,第一个是全局变量u,它是在window这个大环境内声明的,第二个是局部变量,它是在匿名函数function内声明的,因为匿名函数内包含着一个块级作用域,所以我们也可以说匿名函数内包含着一个不同于window的另一个环境。按照我们在上面提到的解析原则,在这个环境内的var变量都会提升到顶部,并且初始化为undefined,所以代码看起来就是上面的那个样子。而解析原则也会对函数提升,但是初始值不是undefined而是该函数本身,也就是说不会改变。那么下面两段代码可以说是同样的效果:
/解析前的函数
(function(){
say();
function say() {
alert('hello world');
}
});
//解析后的同效函数
(function(){
var say = function() {
alert('hello world');
}
say();
});
解析原则还包括对同名函数的覆盖,下面两段代码可以说明解析前后的状态。
//预解析前
(function () {
function say() {
alert('hello world');
} say() function say() {
alert('bonjour la monde');
}
})
//解析后的等效函数
(function(){
var say = function() {
alert('hello world')
}
var say = function() {
alert('bonjour monde')
} say();
});
现在,相信你应该对js的预解析过程有清楚的了解了。需要注意的是,用var和函数命名(function someFun())的方式声明一个函数都没有问题,这取决与项目的需要或者代码的规范或者个人的喜好,但是遇到以上的问题比如用var声明,那么在此之前你是不能够调用它的,而用function name() 方式命名,在同一个环境或者作用域内,你可以在任何地方调用它。
javascript的执行和预解析的更多相关文章
- javascript预解析和作用域
JavaScript解析过程分为两个阶段: 一是:编译阶段.就是JavaScrip预解析阶段,在这个阶段JavaScript解析器将完成把JavaScript脚本代码转换到字节码; 二是:执行阶段.在 ...
- js 预解析
前言 JavaScript是解释型语言是毋庸置疑的,但它是不是仅在运行时自上往下一句一句地解析的呢? 事实上或某种现象证明并不是这样的,通过<JavaScript权威指南>及网上相关资料了 ...
- JS预解析与变量提升
预解析 JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的.JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析过程和代码执行过程 预解析过程 ...
- JavaScript-----11.预解析
1.预解析 1.1引子 //1问 console.log(num);//报错 num未定义 //2问 console.log(num); //undefined 未报错 var num = 10; / ...
- 第112天:javascript中函数预解析和执行阶段
关于javascript中的函数: 1.预解析:把所有的函数定义提前,所有的变量声明提前,变量的赋值不提前 2.执行 :从上到下执行,但有例外(setTimeout,setInterval,aja ...
- javaScript中的小细节-script标签中的预解析
首先介绍预解析,虽然预解析字面意思很好理解,但是却是出坑出的最多的地方,也是bug经常会有的地方,利用好预解析的特性可以解决很多问题,并且提高代码的质量及数量,浏览器在解析代码前会把变量的声明和函数( ...
- js的预解析和代码执行相关规则
JavaScript解析过程分为两个阶段,一个是编译阶段,另外一个就是执行阶段. 1.编译阶段:又称为预解析阶段,在这个阶段JavaScript解释器将完成把JavaScript脚本代码转换到字节码. ...
- Javascript预解析、作用域、作用域链
最近在看js的一些资料,总结一下昨晚看到的js作用域方面的知识,不准确的地方希望留言指正! 先看片段js代码如下: < script type="text/javascript&quo ...
- JavaScript函数之作用域 / 作用链域 / 预解析
关于作用域和作用链域的问题,很多文章讲的都很详细,本文属于摘录自己觉得对自己有价值的部分,留由后用,仅供参考,需要查看详细信息请点击我给出的原文链接查看原文件 做一个有爱的搬运工~~ -------- ...
随机推荐
- 我眼中的项目leader
个人觉得项目leader应该具备一下基础: 1.技术能力 2.领导能力 3.过滤产品不合理需求能力 4.项目周期把控能力
- ssh学习小记
ssh 为Secure SHell 的缩写.OpenSSH: ssh协议的开源实现. SSH协议版本 v1: 基于CRC-32做MAC,不安全:man-in-middle v2:双方主机协议选择安全 ...
- Linux内核【链表】整理笔记(1)
我们都知道Linux内核里的双向链表和学校里教给我们的那种数据结构还是些不一样.Linux采用了一种更通用的设计,将链表以及其相关操作函数从数据本身进行剥离,这样我们在使用链表的时候就不用自己去实现诸 ...
- net软件自动生成开发编程框架编程机器人
有一个.net自动生成平台(编程机器人)推荐给大家,常规几天十几天的工作,机器人几分钟搞定,不写一行代码,留下大把休闲时光,适应于聪明人:不想太累的程序员(看看风景泡泡妞),不想多请人的老板(有限资金 ...
- SQL Server2005索引碎片分析和解决方法
SQL Server2005索引碎片分析和解决方法 本文作者(郑贤娴),请您在阅读本文时尊重作者版权. 摘要: SQL Server,为了反应数据的更新,需要维护表上的索引,因而这些索引会形成碎片.根 ...
- CR LF的由来
学习Esperanto时用到一款叫做Kajero的软件,支持世界语特殊字符编辑. 在Option菜单中有个选项,End of line 列出了四种换行方式 这四种都是由基本CR和LF组成.那么CR和L ...
- 有关tp里搜索框的实现方法
1:
- 正确获得android设备的IP地址
网上此类获得android设备IP地址相关的文章有不少,有一篇是比较通用的,但有一个问题:有些设备默认的是IPv6的地址,那段代码获得的就是IPv6的地址.但这显然不是我们想要的,我们需要的是IPv4 ...
- PHP 定界符使用
在PHP代码中,如果不想一行一行的拼接HTML或者JS的话,那么使用定界符将是最好的帮手! 使用方法: <<<eof .......html/js..... eof; 注意事项:(别 ...
- js queue dequeue clearQueue stop
一.queue( [queueName ], newQueue ) 操作欲执行队列方法 第一个参数是队列名称,不写的话默认是fx 第二个参数可以是一个函数数组,存放所有队列函数,也可以是一个回掉函 ...