详解JS预解析原理
预解析的的不同机制
预解析也叫预声明,是提前解析声明的意思;预解析是针对变量和函数来说的;但是变量和function的的预解析是两套不同的机制;
- 当浏览器加载我们的HTML页面的时候,首先会提供一个供JS代码执行的环境->全局作用域global(浏览器中的全局作用域,也叫顶级作用域是window)
- JS中的内存空间分为两种:栈内存、堆内存
- 栈内存;提供JS代码执行的环境,存储基本数据类型的值;->全局作用域或者私有的作用域其实都是栈内存;
- 堆内存;存储引用数据类型的值(对象是把属性名和属性值储存进去,函数是把函数体内的代码当做字符串储存进去)
- 在当前的作用域中,JS代码执行之前,浏览器首先会默认的把所有代var和function的进行提前的声明或者定义,->“预解析”(也叫变量提升)
var的预解析机制
vara=1
- 1、代码运行之前,先扫描有没有带var关键字的变量名,有的话,为这个变量名在内存里开一个空间;这时候变量名a是不代表任何值的;用undefined来表示;undefined是一个标识符/记号,表示找不到这个变量名所代表的数据;不存在的意思;这个阶段叫变量的声明;
- 2、当代码运行的时候,则给数据1开辟一个内存空间;
- 3、让数据1和变量名a绑定在一起;变量类型指的就是数据类型;按照js语言的原理来说变量类型有undefined类型;但是数据类型是没有undefined这种数据类型的;只有”undecided”这种字符串类型(字符串类型是数据类型的一种);同理也没有unll这个数据类型,但是有”null”这种字符串类型;
varnum; //1、声明(declare):varnum;->告诉浏览器在当前作用域中有一个num的变量了,如果一个变量只是声明了但是没有赋值,默认的值是undefined console.log(num);//->undefined num=12; //2、定义(defined):num=12;->给我们的变量进行赋值 console.log(num);//->12 //变量提前使用的话,就是undefined console.log(testStr);//undefined vartestStr="22222222"
function关键字的预解析步骤
functionfn(){……}
在代码执行之前,把所有的带function关键字的脚本都扫描一遍,然后定义变量;并且同时给变量赋值;
- 1、函数的定义只是保存一些字符串;预解析的时候在内存里保存fn大括号里面的字符串;
- 2、代码运行时候,读到fn()时候,这个时候就是函数的运行;函数的运行,会先开辟一个堆内存把字符串当做代码在堆内存中再次运行,函数产生的作用域内还会再进行预解析和代码运行;
函数如果多次执行;会产生多个作用域;但是产生的多个作用域里面的内容都是相互独立的;互相没有关系;(在原型和原型链时候再仔细研究原理;)
fn(100,200);//->可以在上面执行,因为预解释的时候声明+定义就已经完成了 functionfn(num1,num2){ vartotal=num1+num2; console.log(total); }
总结
1、var和function关键字的在预解析的时候操作还是不一样的
- var->在预解析的时候只是提前的声明了这个变量,只有当代码执行的时候才会完成赋值操作
- function->在预解析的时候会提前的把声明加定义都完成了(在代码执行的时候遇到定义的代码直接的跳过)
2、预解析只发生在当前的作用域下,例如:开始只对window下的进行预解析,只有函数执行的时候才会对函数中的进行预解析;
[重要]刚开始只对window下的进行预解析,fn函数中目前存储的都是字符串,所以vartotal没啥实际的意义,所以不进行预解析->“预解析是发生在当前作用域下的”
综合题;
console.log(obj);//->undefined varobj={name:"xie",age:25}; functionfn(num1,num2){//代码执行到这一行的时候直接的跳过这一块的代码,因为在预解释的时候我们已经完成了声明加定义 vartotal=num1+num2; console.log(total); } varnum1=12; fn(num1,100);//执行fn,把全局变量num1的值赋值给形参num1,把100赋值给形参num2
下面是一个预解析思路
vara, b=0, fn=function(){ vara=b=2; }; fn(); console.log(a,b);
把上面解析成下面就好理解了
vara; window.b=0; window.fn=function(){ //vara=b=2; vara=2;//a是私有的和全局没关系 b=2;//b是全局的 }; fn();//window.fn() console.log(a,b);//undefined2
预解析机制
- 1、不管条件是否成立都要进行预解析
console.log(a);//->undefined if(!!("a"inwindow)){//"a"inwindow->true vara="xie"; } console.log(a);//->xie
例子中的if是不成立的,预解析的时候,碰到非functon内的var,都会声明,无论你写在ifelse还是别的判断里;假设if语句起作用的话,那么第一次log(a)的时候,就会报错了(没有声明的变量,是不能直接用的,除非typeof),而声明并且没有赋值的表现才是undefined;假设不成立;最开始总结的预解析步骤:代码运行之前,先扫描有没有带var关键字的变量名,有的话,为这个变量名,在内存里开一个空间;预解释是发生在代码执行前的,所以if根本阻挡不了预解析;
- 2、预解析只发生在”=“的左边,只把左边的进行预解析,右边的是值是不进行预解析的
匿名函数之函数表达式:把函数定义的部分当做值赋值给一个变量或者元素的事件
fn1();//->undefined()UncaughtTypeError:fnisnotafunctionJS中只有函数可以执行&&JS上面的代码如果报错了,在不进行任何的特殊处理情况下我们下面的代码都不在执行了 varfn1=function(){ console.log("ok"); }; fn1();
//预解释的时候:fn=xxxfff000 fn2();//->"ok" functionfn2(){ console.log("ok"); } fn2();//->"ok"
预解析的时候:varfn1=function()...->fn的默认值是undefined;这里即使有function,也是不能进行预解释的
- 3、函数体中return下面的代码都不在执行了,但是下面的代码需要参加预解析;而return后面的东西是需要处理的,但是由于它是当做一个值返回的,所以不进行预解析;
functionfn(){ console.log(total); returnfunctionsum(){};//return是把函数中的值返回到函数的外面,这里是把function对应的内存地址返回的到函数的外面,例如:returnxxxfff111;函数体中return下面的代码都不在执行了 vartotal=10; console.log(total); }
- 4、匿名函数的function在全局作用域下是不进行预解析的;
匿名函数之自执行函数:定义和执行一起完成了;函数内的声明,只是在函数内使用;
(function(num){ vartestStr="test"+num; console.log(num); })(100); console.log(testStr);//testStrisnotdefined
- 5、在预解析的时候,如果遇到名字重复了,只声明一次。不重复的声明,但是赋值还是要重复的进行的
预解析:
varfn;声明 fn=xxxfff000;[声明]不用了+定义 fn=xxxfff111;[声明]不用了+定义 //->fn=xxxfff111 varfn=12;//window.fn=12 functionfn(){//window.fn=function(){} }
JS中作用域只有两种:
- window全局作用域;
- 函数执行形成的私有作用域;
- {name:“”}if(){}for(){}while(){}switch(){}这些都不会产生作用域;
ES6可以用let形成块级作用域;https://www.nhooo.com/article/67732.htm
面试题
//涉及this的指向和闭包 varnum=20; varobj={ num:37, fn:(function(num){ this.num*=3;//window.num*3=60 //num+=15; varnum=45; returnfunction(){ this.num*=4; num+=20;//调用父作用域的num(45+20) console.log(num); }; })(num),//->把全局变量num的值20赋值给了自执行函数的形参,而不是obj下的30,如果想是obj下的30,我们需要写obj.num }; varfn=obj.fn; fn();//->65,执行了第1次=>window.num=240 obj.fn();//->85闭包(65+20)//执行了第2次=>obj.num=37*4=148 console.log(window.num,obj.num);//240,148
以上就是详解JS预解析原理的详细内容,更多关于JS预解析原理的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。