前言
JavaScript是一种解释性语言,运行JavaScript代码有两个阶段
编译阶段:编译阶段就是我们常说的JavaScript预解释(预处理)阶段。在这个阶段,JavaScript解释器将完成JavaScript脚本代码到字节码的转换执行阶段:在编译阶段,JavaScript解释器借助执行环境将字节码生成为机械代码,并从上到下依次执行。本文以预解释为重点,框架图如下:
首先,什么是预解释
在js中,那些带有var和函数关键字的需要预先解释:
那么什么是预解释呢?即在执行js代码之前,用var关键字和function关键字声明变量,并在内存中进行排列。
在执行预解释:JavaScript代码之前,默认情况下,浏览器将首先声明或定义所有带有var和function的代码
1.理解声明和定义
声明):为var num=告诉浏览器在全局范围内有一个num的变量;如果一个变量只被声明而没有被赋值,默认值是未定义的
定义了:如num=12=为我们的变量赋值。
2.对于有var和函数关键字的,预解释的操作不同。
Var=预解释时只是提前陈述。
函数=预先声明的定义在预解释时完成
3.预解释仅发生在当前范围内。
例如,首先,只有下窗口会被预解释,只有当函数被执行时,函数才会被预解释
第二,范围链
1.如何区分私有变量和全局变量?
1)在全局范围下声明的变量(在预解释时)是全局变量
2)只有函数执行才会产生私有范围,例如对于(){},if(){}和switch(){}不会产生私有范围
3)“私有范围(var声明)”和“函数参数”中声明的变量是私有变量。在私有范围内,执行代码时会遇到一个变量。首先,我们需要确定它是否是私有变量。如果是私有变量,与外界无关;如果不是私有的,则搜索当前范围的父范围;如果没有父范围,则继续搜索,直到找到窗口,即范围链。
让我们举一个例子来区分私有变量和全局变量:
//=变量提升:var a;风险值b;风险值c;测试=AAAFFF111var a=10,b=11,c=12功能测试(a){//=私有范围:a=10 var b;a=1;//=私有变量a=1 var b=2;//=私有变量b=2c=3;//=全局变量c=3 }测试(10);console . log(a);//10 console . log(b);//11 con sole . log(c);//3判断变量是否私有的一个标准是函数中var声明的变量和函数的参数是否都是私有变量。在测试函数中,a是形式参数,var b定义的变量b是私有变量。
2.函数传递参数
这是因为在执行函数时,会先形成一个新的私有作用域,然后执行如下:
1)如果有一个有形的参数,首先给形式参数赋值
2)私人范围内的预解释
3)私有范围内的代码从上到下执行
让我们看一个例子
var total=0;函数fn(num1,num 2){ console . log(total);//-undefined private vartotal=num 1 num 2不能在外部修改;console.log(总计);//-300}fn(100,200);console.log(总计);//-0 Private不能修改3中内存的分类。JS外部
栈内存:用于提供JS代码执行的环境,即作用域(全局作用域/私有作用域)
堆内存:用于存储引用数据类型的值。对象存储属性名称和属性值,函数存储代码字符串。
第三,全球范围内有var和无var的区别
我们先来看下面两个例子:
//示例1 console . log(num);//-undefinedvar num=12;//示例2 console . log(num 2);//-未捕获的引用错误:num2未定义num2=12//无法事先解释。当你看到var num=12时,你可能会认为这只是一个陈述。但是JavaScript实际上把它看作两个声明语句:var num并且num=12第一个定义声明是在预解释阶段做出的。第二个赋值声明将留在原地等待执行阶段。Num2=12相当于给window添加一个名为Num2的属性名,属性值为12;而var num=12相当于将全局变量num添加到全局范围,相当于将属性名num2添加到属性值为12的窗口。两者最大的区别:带有var的可以预解释,所以在赋值前执行时不会报错;没有var的不能预解释,之前执行会报错;
接下来,我们将举一个例子:
//示例1 var total=0;函数fn(){ console . log(total);//undefinedvar total=100;} fn();console.log(总计);//0//示例2var合计=0;函数fn(){ console . log(total);//0 total=100;} fn();console.log(总计);//100示例1中带有var的变量可以在私有范围内预解释,因此第一个控制台键入的值是未定义的。如果私有范围内的某个变量不是私有的,就去上级范围内查找,如果上级没有,就继续查找,直到找到window。示例2中不带var的变量不是私有的,所以请向上级查询。
第四,预先解释无纪律的五种表现
1.预解释时,无论你的条件是否成立,都要用var做一个预先声明。
请看下面的例子:
if(!(“window”中的“num”){ var num=12;//这句话将引用花括号外的全局范围:var num-window . num;} console . log(num);//未定义2。预解释时,只预解释“=”的左右值,不参与预解释。
请看下面的例子:
fn();//错误报告var fn=function(){//窗口下预解释:var fn;console . log(' ok ');};3.自执行功能:定义和执行一起完成。
自执行函数定义的函数不在全局范围下预解释,代码执行到这个位置时定义和执行一起完成。常见的形式如下:
(function(num){ })(10);~ function(num){ }(10);function(num){ }(10);-function(num){ }(10);function(num){ }(10);4.虽然函数体中return下面的代码不再执行,但需要预解释;Return后面是我们返回的值,所以不做预解释;
函数fn(){//预解释:var numconsole . log(num);//-undefinedreturn函数(){ };var num=100}5.函数声明和变量声明都将被提升。但是一个值得注意的细节(可能出现在带有多个“重复”声明的代码中)是,首先提升函数,然后提升变量。预释时,名称已申报的,无需再次申报,但需重新分配;让我们先看两个简单的例子:
//示例1函数a(){ } var a console . log(a的类型)//' function '//示例2 var c=1函数c(c){ console . log(c)var c=3 } c(2)//Unknown type error : c不是函数。当函数声明和变量声明都提升时,函数声明的优先级更高。最后,变量声明将被函数声明覆盖,但是它可以被重新赋值,所以前面的例子可以等价于
函数c(c){ console . log(c)var c=3 } c=1c(2)接下来,让我们看两个更复杂的主题:
//示例3fn();函数fn(){ console . log(1);};fn();var fn=10fn();函数fn(){ console . log(2);};fn();1.在预解释的开始,函数声明和赋值走到了一起,fn就是function fn(){ console . log(1);};遇到var fn=10不会重新声明,但遇到函数fn(){ console . log(2);}将从重新分配,因此fn()的值在开始时为2
2.再次执行fn();值是相同还是2
3.fn被重新分配给10,因此在运行fn()时报告了一个错误,以下语句没有再次执行。
//示例4 alert(a);(a );var a=3;函数a(){ alert(10)} alert(a);a=6;a(1)。函数声明优先于变量声明。预解释时,函数声明和赋值合在一起,A是函数a(){alert(10)},然后遇到var a=3,不需要重复声明,所以先弹出函数a(){alert(10)}。
2.a(),执行函数,然后弹出10
3.然后执行var a=3。所以警戒(a)是显示3
4.由于A不是一个函数,所以在执行A()时会报告一个错误。
参考文章
JavaScript中的预解析http://heartwalker.cc/2016/04/04/js作用域第2部分-预解析/总结
以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。有问题可以留言交流。谢谢你的支持。