详解JS预解析原理


Posted in Javascript onJune 16, 2020

预解析的的不同机制

预解析也叫预声明,是提前解析声明的意思;预解析是针对变量和函数来说的;但是变量和function的的预解析是两套不同的机制;

  • 当浏览器加载我们的HTML页面的时候,首先会提供一个供JS代码执行的环境->全局作用域global(浏览器中的全局作用域,也叫顶级作用域是window)
  • JS中的内存空间分为两种:栈内存、堆内存
  1. 栈内存;提供JS代码执行的环境,存储基本数据类型的值;->全局作用域或者私有的作用域其实都是栈内存;
  2. 堆内存;存储引用数据类型的值(对象是把属性名和属性值储存进去,函数是把函数体内的代码当做字符串储存进去)
  • 在当前的作用域中,JS代码执行之前,浏览器首先会默认的把所有代var和function的进行提前的声明或者定义,->“预解析”(也叫变量提升)

var的预解析机制

var a=1

  • 1、代码运行之前,先扫描有没有带var关键字的变量名,有的话,为这个变量名在内存里开一个空间;这时候变量名a是不代表任何值的;用undefined来表示;undefined是一个标识符/记号,表示找不到这个变量名所代表的数据;不存在的意思;这个阶段叫变量的声明;
  • 2、当代码运行的时候,则给数据1开辟一个内存空间;
  • 3、让数据1和变量名a绑定在一起;变量类型指的就是数据类型;按照js语言的原理来说变量类型有undefined类型;但是数据类型是没有undefined这种数据类型的;只有”undecided”这种字符串类型(字符串类型是数据类型的一种);同理也没有unll这个数据类型,但是有”null”这种字符串类型;
var num;
//1、声明(declare):var num; ->告诉浏览器在当前作用域中有一个num的变量了,如果一个变量只是声明了但是没有赋值,默认的值是undefined
console.log(num);//->undefined
num = 12;
//2、定义(defined):num=12; ->给我们的变量进行赋值
console.log(num);//->12

//变量提前使用的话,就是undefined
console.log(testStr);//undefined
var testStr="22222222"

function 关键字的预解析步骤

function fn(){……}

在代码执行之前,把所有的带function关键字的脚本都扫描一遍,然后定义变量;并且同时给变量赋值;

  • 1、函数的定义只是保存一些字符串;预解析的时候在内存里保存fn大括号里面的字符串;
  • 2、代码运行时候,读到fn()时候,这个时候就是函数的运行;函数的运行,会先开辟一个堆内存把字符串当做代码在堆内存中再次运行,函数产生的作用域内还会再进行预解析和代码运行;

函数如果多次执行;会产生多个作用域;但是产生的多个作用域里面的内容都是相互独立的;互相没有关系;(在原型和原型链时候再仔细研究原理;)

fn(100,200);//->可以在上面执行,因为预解释的时候声明+定义就已经完成了 
function fn(num1, num2) { 
	var total = num1 + num2; 
	console.log(total);
}

总结

1、var和function关键字的在预解析的时候操作还是不一样的

  • var -> 在预解析的时候只是提前的声明了这个变量,只有当代码执行的时候才会完成赋值操作
  • function -> 在预解析的时候会提前的把声明加定义都完成了(在代码执行的时候遇到定义的代码直接的跳过)

2、预解析只发生在当前的作用域下,例如:开始只对window下的进行预解析,只有函数执行的时候才会对函数中的进行预解析;

[重要]刚开始只对window下的进行预解析,fn函数中目前存储的都是字符串,所以var total没啥实际的意义,所以不进行预解析-> “预解析是发生在当前作用域下的”

综合题;

console.log(obj);//->undefined
	var obj = {name: "xie", age: 25};
 function fn(num1, num2) {//代码执行到这一行的时候直接的跳过这一块的代码,因为在预解释的时候我们已经完成了声明加定义
 var total = num1 + num2;
 console.log(total);
 }
 var num1 = 12;
 fn(num1, 100);//执行fn,把全局变量num1的值赋值给形参num1,把100赋值给形参num2

下面是一个预解析思路

var a,
 b = 0,
 fn = function () {
 var a = b = 2;
 };
fn();
console.log(a, b);

把上面解析成下面就好理解了

var a;
window.b = 0;
window.fn = function () {
 //var a = b = 2;
 var a = 2;//a是私有的和全局没关系
 b = 2;//b是全局的
};
fn();//window.fn()
console.log(a, b);//undefined 2

预解析机制

  • 1、不管条件是否成立都要进行预解析
console.log(a);//->undefined
if (!!("a" in window)) {//"a" in window -> true
 var a = "xie";
}
console.log(a);//->xie

例子中的if是不成立的,预解析的时候,碰到非functon内的var,都会声明,无论你写在if else 还是别的判断里; 假设if语句起作用的话,那么第一次log(a)的时候,就会报错了(没有声明的变量,是不能直接用的,除非typeof ),而声明并且没有赋值的表现才是undefined;假设不成立; 最开始总结的预解析步骤:代码运行之前,先扫描有没有带var关键字的变量名,有的话,为这个变量名,在内存里开一个空间;预解释是发生在代码执行前的,所以if根本阻挡不了预解析;

  • 2、预解析只发生在”=“的左边,只把左边的进行预解析,右边的是值是不进行预解析的

匿名函数之函数表达式:把函数定义的部分当做值赋值给一个变量或者元素的事件

fn1();//->undefined() Uncaught TypeError: fn is not a function JS中只有函数可以执行 && JS上面的代码如果报错了,在不进行任何的特殊处理情况下我们下面的代码都不在执行了
var fn1 = function () {
 console.log("ok");
};
fn1();
//预解释的时候:fn=xxxfff000
fn2();//->"ok"
function fn2() {
 console.log("ok");
}
fn2();//->"ok"

预解析的时候:var fn1 = function()... ->fn的默认值是undefined;这里即使有function,也是不能进行预解释的

  • 3、函数体中return下面的代码都不在执行了,但是下面的代码需要参加预解析;而return后面的东西是需要处理的,但是由于它是当做一个值返回的,所以不进行预解析;
function fn() {
 console.log(total);
 return function sum() {};//return是把函数中的值返回到函数的外面,这里是把function对应的内存地址返回的到函数的外面,例如:return xxxfff111;函数体中return下面的代码都不在执行了
 var total = 10;
 console.log(total);
}
  • 4、匿名函数的function在全局作用域下是不进行预解析的;

匿名函数之自执行函数:定义和执行一起完成了;函数内的声明,只是在函数内使用;

(function(num){
 var testStr="test"+num;
 console.log(num);
})(100);

console.log(testStr);// testStr is not defined
  • 5、在预解析的时候,如果遇到名字重复了,只声明一次。 不重复的声明,但是赋值还是要重复的进行的

预解析:

var fn; 声明
 fn = xxxfff000; [声明]不用了+定义
 fn = xxxfff111; [声明]不用了+定义
 // ->fn=xxxfff111
 var fn = 12;//window.fn=12
 function fn() {//window.fn=function(){}
 }

JS中作用域只有两种:

  • window全局作用域;
  • 函数执行形成的私有作用域;
  • {name:“”} if(){} for(){} while(){} switch(){} 这些都不会产生作用域;

ES6可以用let形成块级作用域;https://3water.com/article/67732.htm

面试题

// 涉及this的指向和闭包
var num = 20;
var obj = {
	num: 37,
	fn: (function (num) {
		this.num *= 3; // window.num * 3 = 60
		// num += 15; 
		var num = 45;
		return function () {
			this.num *= 4; 
			num += 20; // 调用父作用域的num (45+20)
			console.log(num);
		};
	})(num), //->把全局变量num的值20赋值给了自执行函数的形参,而不是obj下的30,如果想是obj下的30,我们需要写obj.num
};
var fn = 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预解析原理的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
通过修改referer下载文件的方法
May 11 Javascript
js动态控制table的tr、td增加及删除的具体实现
Apr 30 Javascript
js实现最短的XML格式化工具实例
Mar 12 Javascript
JS+CSS实现大气清新的滑动菜单效果代码
Oct 22 Javascript
js实现可控制左右方向的无缝滚动效果
May 29 Javascript
ES6中数组array新增方法实例总结
Nov 07 Javascript
vue-cli3跨域配置的简单方法
Sep 06 Javascript
如何通过shell脚本自动生成vue文件详解
Sep 10 Javascript
Vue退出登录时清空缓存的实现
Nov 12 Javascript
Vue学习之组件用法实例详解
Jan 06 Javascript
js实现跳一跳小游戏
Jul 31 Javascript
微信小程序canvas实现签名功能
Jan 19 Javascript
深入了解JS之作用域和闭包
Jun 16 #Javascript
JS数组及对象遍历方法代码汇总
Jun 16 #Javascript
浅谈Vue 函数式组件的使用技巧
Jun 16 #Javascript
原生JS实现天气预报
Jun 16 #Javascript
vue实现公告栏文字上下滚动效果的示例代码
Jun 16 #Javascript
原生JS实现无缝轮播图片
Jun 24 #Javascript
如何利用Node.js与JSON搭建简单的动态服务器
Jun 16 #Javascript
You might like
php代码书写习惯优化小结
2013/06/20 PHP
从零开始学YII2框架(六)高级应用程序模板
2014/08/20 PHP
php实现三级级联下拉框
2016/04/17 PHP
从ThinkPHP3.2.3过渡到ThinkPHP5.0学习笔记图文详解
2019/04/03 PHP
锋利的jQuery 第三章章节总结的例子
2010/03/23 Javascript
Jquery下attr和removeAttr的使用方法
2010/12/28 Javascript
JS中把字符转成ASCII值的函数示例代码
2013/11/21 Javascript
js闭包的用途详解
2014/11/09 Javascript
jquery实现图片水平滚动效果代码分享
2015/08/26 Javascript
深入浅出ES6新特性之函数默认参数和箭头函数
2016/08/01 Javascript
js面向对象编程总结
2017/02/16 Javascript
微信小程序ajax实现请求服务器数据及模版遍历数据功能示例
2017/12/15 Javascript
对vue v-if v-else-if v-else 的简单使用详解
2018/09/29 Javascript
Node.js 在本地生成日志文件的方法
2020/02/07 Javascript
[01:33:59]真人秀《加油 DOTA》 第六期
2014/09/09 DOTA
python获取当前目录路径和上级路径的实例
2018/04/26 Python
Python实现简单的用户交互方法详解
2018/09/25 Python
Python实现图像的垂直投影示例
2020/01/17 Python
TensorFlow加载模型时出错的解决方式
2020/02/06 Python
Python 删除List元素的三种方法remove、pop、del
2020/11/16 Python
HTML5 拖放(Drag 和 Drop)详解与实例代码
2017/09/14 HTML / CSS
萌新的HTML5 入门指南
2020/11/06 HTML / CSS
巴西儿童时尚购物网站:Dinda
2019/08/14 全球购物
体育老师的教学自我评价分享
2013/11/19 职场文书
清明节扫墓活动方案
2014/03/02 职场文书
大型活动组织方案
2014/05/10 职场文书
新闻发布会策划方案
2014/06/12 职场文书
项目委托协议书(最新)
2014/09/13 职场文书
公安交警个人对照检查材料思想汇报
2014/10/01 职场文书
学校党的群众路线教育实践活动个人整改方案
2014/10/31 职场文书
仓管员岗位职责范本
2015/04/01 职场文书
公司仓管员岗位职责
2015/04/01 职场文书
2016年3月份红领巾广播稿
2015/12/21 职场文书
教师读书活动心得体会
2016/01/14 职场文书
python opencv通过按键采集图片源码
2021/05/20 Python
MySQL实现配置主从复制项目实践
2022/03/31 MySQL