javscript执行顺序(笔记)

先了解一下变量提升

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

以上语句并不会报错,只是提示undefined。实际运行过程:

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

变量提升
JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting);

1.表示变量a已声明,但还未赋值。但是变量提升只对var命令声明的变量有效,如果一个变量不是用var命令声明的,就不会发生变量提升。

console.log(aa);
aa =1;

以上代码将会报错:ReferenceError: aa is not defined。
2. 与普通变量一样,js里的function也可看做变量,也存在变量提升情况:

a();

function a(){
    console.log(1);
};

表面上,上面代码好像在声明之前就调用了函数a。但是实际上,由于“变量提升”,函数a定义部分被提升到了代码头部,也就是在调用之前已经声明了。但是,如果采用赋值语句定义函数,JavaScript就会报错:

a();

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

// TypeError: a is not a function

因为,实际运行过程:

var a;
a();

a = function(){
    console.log(1);
};

了解了变量提升,下面来看javascript执行顺序

对于一个HTML文档,浏览器的解析顺序为:按照文档流,从上到下逐步解析页面的结构。JavaScript代码作为通过标签嵌入或引入的脚本,也HTML文档的组成部分。因此,JavaScript代码在装载时的执行顺序也是根据脚本标签

但是,浏览器加载JavaScript时有个特点,那就是载入之后立即就会执行(先编译后执行),因为JavaScript可能会影响DOM树的结构,所以浏览器在执行完后才能继续加载下面的HTML内容。也就是说,浏览器下载并执行JavaScript的过程会阻塞DOM树的继续建立。所以,引入的多个js文件,会按顺序分开执行。同样的,对于不同

由于JavaScript通常需要操作DOM,所以,一般把JavaScript放在前或者文档结尾处引入。若需要在中引入,可以通过修改window.onload或者document.ready事件,强制等到DOM加载完成后再执行相关函数。

1.代码如下:

<scripttype="text/javascript">       
functionHello() {        
alert("Hello");  
}       
Hello();     
functionHello() {  
alert("Hello World");   
}       
Hello();   
</script>

我们会看到这样的结果:连续输出了两次Hello World。
而非我们想象中的Hello和Hello World。
这是因为Javascript并非完全的按顺序解释执行,而是在解释之前会对Javascript进行一次“预编译”,在预编译的过程中,会把定义式的函数优先执行,也会把所有var变量创建,默认值为undefined,以提高程序的执行效率。
也就是说上面的一段代码其实被JS引擎预编译为这样的形式:

<scripttype="text/javascript">       
var Hello = function() {          
alert("Hello");       
}      
Hello = function() {
           alert("Hello World"); 
      }     
Hello();    
Hello(); 
</script>

我们可以通过上面的代码很清晰地看到,其实函数也是数据,也是变量,我们也可以对“函数“进行赋值(重赋值)。
当然,我们为了防止这样的情况,也可以这样:

<scripttype="text/javascript">     
function Hello() {       
alert("Hello");      
}       
Hello(); 
</script>  
<scripttype="text/javascript">  
function Hello() {         
alert("Hello World");    
}      
Hello(); 
</script>

这样,程序被分成了两段,JS引擎也就不会把他们放到一起了。
当JavaScript引擎解析脚本时,它会在预编译期对所有声明的变量和函数进行处理。
做如下处理:

  1. 在执行前会进行类似“预编译”的操作:首先会创建一个当前执行环境下的活动对象,并将那些用var申明的变量设置为活动对象的属性,但是此时这些变量的赋值都是undefined,并将那些以function定义的函数也添加为活动对象的属性,而且它们的值正是函数的定义。
  2. 在解释执行阶段,遇到变量需要解析时,会首先从当前执行环境的活动对象中查找,如果没有找到而且该执行环境的拥有者有prototype属性时则会从prototype链中查找,否则将会按照作用域链查找。遇到var a = …这样的语句时会给相应的变量进行赋值(注意:变量的赋值是在解释执行阶段完成的,如果在这之前使用变量,它的值会是undefined) 所以,就会出现当JavaScript解释器执行下面脚本时不会报错:
alert(a);                            // 返回值undefined
var a =1;

alert(a);                            // 返回值1

由于变量声明是在预编译期被处理的,所以在执行期间对于所有代码来说,都是可见的。但是,你也会看到,执行上面代码,提示的值是undefined,而不是1。这是因为,变量初始化过程发生在执行期,而不是预编译期。在执行期,JavaScript解释器是按着代码先后顺序进行解析的,如果在前面代码行中没有为变量赋值,则JavaScript解释器会使用默认值undefined。由于在第二行中为变量a赋值了,所以在第三行代码中会提示变量a的值为1,而不是undefined。

同理,下面示例在函数声明前调用函数也是合法的,并能够被正确解析,所以返回值为1。

f();                                 // 调用函数,返回值1
function f(){

    return 1;

}

但是,如果按下面方式定义函数,则JavaScript解释器会提示语法错误。

f();                                 // 调用函数,返回语法错误
var f = function(){

    alert(1);

}

这是因为,上面示例中定义的函数仅作为值赋值给变量f,所以在预编译期,JavaScript解释器只能够为声明变量f进行处理,而对于变量f的值,只能等到执行期时按顺序进行赋值,自然就会出现语法错误,提示找不到对象f。

另外一些列子:

<script type="text/javascript">
/*在预编译过程中func是window环境下的活动对象中的一个属性,值是一个函数,覆盖了undefined值*/

alert(func); //function func(){alert("hello!")}

var func = "this is a variable"

function func(){

alert("hello!")

}

/*在执行过程中遇到了var重新赋值为"this is a variable"*/

alert(func);  //this is a variable

</script>
var name = "feng";
function func()
{
/*首先,在func环境内先把name赋值为undefined,然后在执行过程中先寻找func环境下的活动对象的name属性,此时之前已经预编译值为undefined,所以输出是undefined,而不是feng*/
alert(name);  //undefined
var name = "JSF";
alert(name);  //JSF
}
func();
alert(name);//feng
最后执行结果:  undefined ,  JSF,  feng

注意:(1)函数声明的提升优先于变量声明的提升;(2)重复的var声明会被忽略掉,但是重复的function声明会覆盖掉前面的声明。

在预处理阶段,声明的变量的初始值是undefined, 采用function声明的函数的初始内容就是函数体的内容。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值