预编译

函数有一些看不到的属性
fun.[[scope]]
scope就是看不到的属性,这个属性是函数调用的时候生成的,这个属性装的就是函数的作用域

js的执行过程
1.语法检测 检测你的代码有没有基本的语法错误
2.预编译(全局预编译,局部预编译)
3.逐行执行

目标理解预编译过程,作用域,作用域链

作用域
1.全局作用域
2.函数作用域

预编译-全局
在逐行执行之前,语法检测
没有语法错误则进行预编译

	 var  a;
	 function fun(){};
	 function a(){};

预编译-全局,发生在代码执行前一刻,会发生三个步骤
1.生成一个空对象GO(global object),GO = {}
2.向GO里添加所有不在函数体内的var声明的变量名作为GO对象的属性名,值为undefined
GO = {
a : undefined
}
3.向GO对象里添加所有没被其他函数包裹的函数声明,函数名作为GO对象的属性名,值为函数体
Go = {
a : undefined,
fun:function(){};
a:function(){};
}

如果遇到函数名与变量名同名,则将变量的undefined覆盖掉
Go = {
a:function(){};
fun:function(){};
}

如果变量遇到同名,则不作改变
如果遇到函数名与函数名同名,则从上至下以最后一个同名函数的函数体覆盖

	// 1.会生成一个对象,这个对象装的就是作用域,称为GO(global object)。当全部挂载完成以后,然后代码再去逐行执行
		GO = {
		}
		// 2.分析var声明。
			变量名作为GO对象的属性名,值为undefined
		go = {
			a : undefined
		 }
		// 3.分析函数声明
			// 函数名作为GO对象的属性名,值为函数体
			// 如果遇到同名的,直接干掉
			go = {
			 	a : function,
				fun : function fun(){
			 	},
			abc : function,
			}
			// 走到第27行的时候,a产生一次赋值
			// 此时go对象变成了
			 go = {
			 	a : 100,
				fun : function fun(){
				},
		 	abc : function,
			 }

	// 逐行执行
	// 看着go对象里面的内容执行

全局预编译完成后,则开始逐行执行
执行到函数调用,局部预编译开始
局部预编译分为四个步骤
1.执行函数体的前一刻生成AO 对象(活动对象) AO = {}
2.将函数形参添加到AO 对象中,赋值为实参值
3.将函数体内所有变量声明找出,赋值undefined,如果遇到同名(包括形参名)不作改变
4.将函数体内的函数声明找出,函数名作为AO对象的属性名,值为函数体,遇到同名则覆盖

例题:
// 第一题

	function test(a,b){
		console.log(a);  //function a(){};
		console.log(b);  //undefine
		var b = 234;      //b从undefinde,被赋值234
		console.log(b);    //234
		a = 123;             //a为转化全局属性,属性值为123
		console.log(a);      //123
		function a(){};      
		var a;            //这里的a在预编译时已经提升上去了,且在逐行执行过程中被赋值为123
		b = 234;           //b转化为全局变量,赋值为234
		var b = function(){};      //b被重新赋值
		console.log(a);          //打印的还是123
		console.log(b);			//function(){}; 
	}	
	test(1);

// 1.分析GO,生成自己的GO对象
// GO = {}
// 2.分析变量声明,没有就直接略过
// GO = {}
// 3.分析函数声明
// GO = {
// test : function test(a,b)
// }

1.在执行前一刻生成AO对象
AO = {}
2.将函数体中的形参和变量声明找出来,在AO 对象中初始属性值为undefined
AO = {
a : undefine
b : undefine
}
3.将形参与实参统一
AO = {
a : 1
b : undefine
}
4.分析函数声明,函数名为AO 对象的属性名,值为函数体
AO = {
a :function a(){};
b : undefine
}

	// 第二题
	console.log(test);
	function test(test){
		console.log(test);  //打印输出为预编译后的结果  :function test(){}
		var test = 234;     //重新赋值为234
		console.log(test);   //234
		function test(){}    
	}
	test(1);
	var test = 123;     //在函数体AO对象中找得到test,则用函数体内的test,找不到则在GO中找
	
1.分析GO,生成自己的GO对象			
	 GO = {}
	2.分析变量声明,找出全局变量声明,将变量声明的名作为GO对象的属性名,赋值为GO对象的属性值
    GO = {
	test : 123
    }
3.分析函数声明,找出全局函数声明,将函数声明的名作为GO对象的属性名,赋值为GO对象的属性值,并覆盖在GO对象中的同名的属性值
    GO = {
    	test : function test(test){
		console.log(test);
		var test = 234;
	console.log(test);
	function test(){}
 }
}

// 1.在执行前一刻生成AO对象
// AO = {}
// 2.将函数体中的形参和变量声明找出来,在AO 对象中初始属性值为undefined,遇同名不做改变
// AO = {
// test : undefined
// }
// 3.将形参与实参统一
// AO = {
// test : 1
// }
// 4.分析函数声明,函数名为AO 对象的属性名,属性值为函数体,同名则覆盖掉
// AO = {
// test : function test(){}
// }
*/

	// 第三题
	function test(){
		console.log(b);  //undefined
		if(a){
			var b = 100;   				
		}
		c = 234;        //c为全局变量,在GO中,属性名为c,赋值为234
		console.log(c);   //234
	}
	var a;  //undefined
	test();
	a = 10;  //10
	test();
	console.log(c);  //234

1.分析GO,生成自己的GO对象
GO = {}
2.分析变量声明,找出全局变量声明,将变量声明的名作为GO对象的属性名,赋值为GO对象的属性值
GO = {
a : undefined
}
3.分析函数声明,找出全局函数声明,将函数声明的名作为GO对象的属性名,赋值为GO对象的属性值,并覆盖在GO对象中的同名的属性值
GO = {
a : undefined
test : function test(){
}

1.在执行前一刻生成AO对象
AO = {}
2.将函数体中的形参和变量声明找出来,在AO 对象中初始属性值为undefined,遇同名不做改变
AO = {
b : undefined
}
3.将形参与实参统一
AO = {
b : undefined
}
4.分析函数声明,函数名为AO 对象的属性名,属性值为函数体,同名则覆盖掉
AO = {
b : undefined
}

	// 第四题
	function bar(){
		return foo;
		foo = 10;
		function foo(){};
		var foo = 11;
	}
	console.log(bar());
		
//		1.分析GO,生成自己的GO对象			
//		 GO = {}	
//		2.分析变量声明,找出全局变量声明,没有就直接略过
//		 GO = {}	
//	3.分析函数声明,找出全局函数声明,将函数声明的名作为GO对象的属性名,赋值为GO对象的属性值,并覆盖在GO对象中的同名的属性值
//	    GO = {
//	    	bar : function bar(){
//			return foo;
//			foo = 10;
//			function foo(){};
//			var foo = 11;
//		  } 
//	    }		   
	
	//		 1.在执行前一刻生成AO对象
	//		AO = {}
	//		2.将函数体中的形参和变量声明找出来
	//		AO = {
	//      	foo : undefined 
	//     }
//       3.将形参与实参统一,没有就略过
//		AO = {
//      	foo : undefined 
//     }
//       4.分析函数声明,函数名为AO 对象的属性名,属性值为函数体,同名则覆盖掉
//       AO = {
//	        foo : function foo(){};
//     } 		

全局预编译
总结变量声明提升,函数整体提升
变量声明提升:变量名拿到最上面去,对变量的赋值,等预编译完成后,执行的时候再赋值给他,提升上去后,就相当于在js代码的最上面声明了变量却没有赋值
函数整体提升:将整个函数声明全部提升到顶端,提升上去后,就相当于在js代码的最上面声明函数、且有函数值
注意:这两句话不能颠倒,且与函数名同名,则被函数函数覆盖,变量名与变量名同名,则不作改变

局部预编译
总结将形参和实参统一,然后变量声明提升,函数整体提升,提升到函数体的最上面,如果变量名与形参同名,形参不作改变。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值