浏览器如何实现变量提升var和function

变量提升

  • 变量提升:在当前上下文中(全局/私有/块级),JS代码自上而下执行之前,浏览器会提前处理一些事情(可以理解为词法解析的一个环节,词法解析一定发生在代码执行之前),会把当前上下文中所有带VAR/FUNCTION关键字的进行提前的声明或者定义
  • 带var的只会提前的声明带function会提前的声明定义
  • 使用变量提升的作用:没有给变量定义值就使用不会报错,不影响js执行。
var a=10;

声明declare:var a;
定义defined:a=10;


代码执行之前:全局上下文中的变量提升–var

浏览器在以下js代码执行之前对var关键字进行提前声明

var a;   默认值是undefined,var只声明不定义
   console.log(a); 
   //=>undefined  此时浏览器打印undefined,而不是报错:a is not defined
   var a = 12;
    //=>创建值12  不需要再声明a了(变量提升阶段已经声明了,不会重新处理) 这一步只做了赋值操作,a=12
   a = 13; 
   //全局变量a=13  这一步修改了全局变量值
   console.log(a); //=>13
console.log(a); 
// 报错 =>Uncaught ReferenceError: a is not defined 没有var 关键字不会做变量提升
a = 13;
console.log(a);

代码执行之前:全局上下文中的变量提升–function

function func(){}     相当于func=函数   在这个阶段声明和赋值都做了
func();//OK  js没有执行之前,变量提升阶段遇到function关键字,声明了func,并给他赋值func=函数,所以执行func()不会报错。
function func() {
	var a = 12;
	console.log('OK');
} 
  • 真实项目中建议使用函数表达式创建函数,因为这样在变量提升阶段只会声明func,不会赋值
  • 这种创建函数方式符合代码编程的逻辑
func()  //报错 func is not a function,不会再往下执行
var func=function(){
	console.log('ok')
}
var func=function(){
	console.log('ok')
}
func()  //OK  只能放在函数下方执行,符合代码编程的逻辑

匿名函数具名化

  1. 把原本作为值的函数表达式匿名函数“具名化”(虽说是起了名字,但是这个名字不能在外面访问 =>也就是不会在当前当下文中创建这个名字)
  2. 当函数执行,在形成的私有上下文中,会把这个具名化的名字做为私有上下文中的变量(值就是这个函数)来进行处理

作用:

  • 规范
  • 可以递归
var func = function AAA() {
	console.log('OK');
 	console.log(AAA); //=>当前函数
 	AAA(); //递归调用   而不用严格模式下都不支持的 arguments.callee 了 	
 };
 AAA();  //=>Uncaught ReferenceError: AAA is not defined
 func()
setTimeout(function func() {
    func();//递归调用
}, 1000);

EC(G)变量提升 只有var/function会变量提升(ES6中的let和const不会)

console.log(a); 
//报错=>Uncaught ReferenceError: Cannot access 'a' before initialization  不能在LET声明之前使用变量
let a = 12;
a = 13;
console.log(a);
  • 基于var或者function在“全局上下文”中声明的变量(全局变量)会“映射”到GO(全局对象window)上一份,作为他的属性;而且接下来是一个修改,另外一个也会跟着修改;
var a = 12;
 console.log(a); //=>12  全局变量
 console.log(window.a); //=>12 映射到GO上的属性a

 window.a = 13;
 console.log(a); //=>13 映射机制是一个修改另外一个也会修改

EC(G):全局上下文中的变量提升–有if(){}条件或{}

  • 不论条件是否成立,都要进行变量提升(细节点:条件中带FUNCTION的在新版本浏览器中只会提前声明,不会在提前的赋值了)
  • [老版本]:如IE10以下等
    var a;
    func=函数;
  • [新版本]
    var a; 全局上下文中声明一个a也相当于 window.a
    func;
//全局上下文遇到if ,进行变量提升,
//新版本 var a=undefined,function func=undefined
console.log(a, func); //=>undefined undefined
if (!("a" in window)) { // 变量提升阶段已经声明了a,true 所以这段代码不会执行
	//=>"a" in window 检测a是否为window的一个属性   !TRUE => FALSE
	var a = 1;
	function func() {}
}
console.log(a); //=>undefined
//EC(G)变量提升
//fn=>1
// =>2
//var fn;  已经声明过了
// =>4
// =>5
//全局上下文中有一个全局变量fn,值是输出5的函数(此时window.fn=>5)

fn(); //=>5
function fn(){ console.log(1); }  //=>不再处理,变量提升阶段搞过了
fn(); //=>5
function fn(){ console.log(2); }
fn(); //=>5
var fn = function(){ console.log(3); }  //=>var fn不用在处理了,但是赋值在变量提升阶段没处理过,此处需要处理  fn=window.fn=>3
fn(); //=>3
function fn(){ console.log(4); }
fn(); //=>3
function fn(){ console.log(5); }
fn(); //=>3
 var foo = 1;
function bar() {//执行函数,在函数执行的私有作用域中也会进行变量提升
	if (!foo) {//变量提升遇到条件,声明var foo=undefined; 此时foo作为函数私有作用域的变量,与函数外边变量无关
		var foo = 10;
	}
	console.log(foo);
}
bar(); //10

在这里插入图片描述

//EC(G)变量提升:var a;function a;
var a = 0;
if (true) {
    a = 1;
    function a() {};
    a = 21;
    console.log(a)//21
}
console.log(a); //1

在这里插入图片描述

var a = 0;
if (true) {
	a = 1; //=>Uncaught ReferenceError: Cannot access 'a' before initialization
	let a = 10;
	a = 21;
	console.log(a)
}
console.log(a);
// Uncaught SyntaxError: Identifier 'a' has already been declared
console.log(a); 
{
	console.log(a);
	var a = 10;
	function a() {}
	console.log(a);
}
console.log(a);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值