深入理解JS预编译——AO对象及GO对象

JS预编译

JS有两个特性,一个是单线程,一个是解释性语言。不同于编译性语言,解释性语言通常理解为不整体编译,由解释器解释一句执行一句。但JS不是直接对着代码解释执行,在解释执行之前,需要进行其他的步骤。

JS运行步骤:

  1. 语法分析
  2. 预编译
  3. 解释执行

预编译有个特点:任何变量,如果未声明就赋值,那该变量为全局变量,即暗示全局变量(imply global)。并且所有的全局变量都是window的属性。

function fn(){
    
    
	var a = b =123;
}
test();

解析:这是一个连续赋值的过程,赋值是从右向左赋值,先把123赋给b,再把b赋给a,其实导致b未经声明就赋值了,所以这个b属于window的属性。

AO对象

AO对象全称为:activation object (活跃对象/执行期上下文),在函数执行前执行函数预编译,此时会产生一个AO对象,AO对象保存该函数的参数变量。

函数预编译步骤

  1. 创建AO对象
  2. 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
  3. 将实参的值赋值给形参。
  4. 在函数体里面找函数声明,函数名作为AO对象的属性名,值赋值给函数体。(若参数名和函数名重叠,则函数体值会覆盖参数值)

实战分析

   function test(a) {
    
    
		console.log(a);//function a(){}
		var a = 2;
		console.log(a);//2
		function a () {
    
    }
		console.log(a);//2
		var b = function () {
    
    };
		console.log(b);//function () {}
		function d(){
    
    }
	}
	test(1);
    </script>

test函数执行过程分析:
1、创建AO对象

AO {
    
    
	
}

2、找AO对象的属性名

AO{
    
    
	a:undefined
	b:undefined 
}	

3、将实参值赋值给形参

AO{
    
    
	a:1
	b:undefined
}	

4、处理函数里面的声明函数

AO{
    
    
	a:function a () {
    
    } //变量名一样,值覆盖
	b:undefined; 
	d:function d () {
    
    };
}

此时函数预编译已经完成的,预编译后执行代码:
第一条执行的是控制台打印出a的值,所以输出function a () {};
第二条语句赋值给a,则AO对象中a的值被覆盖为2;

AO{
    
    
	a:2 
	b:undefined; 
	d:function d () {
    
    };
}

第三条语句控制台打印a的值为2;
第四条为声明,预编译处理过所以直接跳过;
第五条打印出a的值,一样为2;
第六条为赋值,赋值b的值为function () {};

AO{
    
    
	a:2 
	b:function () {
    
    }; 
	d:function d () {
    
    };
}

第七条打印出b的值function () {};
第八条声明,预编译处理过所以直接跳过;

GO对象

GO对象全称为 global object(全局对象,等同于window),在开始预编译时产生的对象,比AO对象先产生,用于存放全局变量,也称为全局作用域。

预编译三步骤

  1. 生成GO对象
  2. 将变量声明的变量名当做GO对象的属性名,值为undefinded
  3. 将声明函数的函数名当做GO对象的属性名,值为函数体

实战分析

function test(){
    
    
	console.log(b);//undefined
	if(a){
    
    
		var b = 100;
	}
	c =234
	console.log(c);//234
}
var a ;
test();
a =10;
console.log(c);//234

实战分析:
1、创建GO对象

GO{
    
    

}

2、将声明变量添加进GO对象内,值为undefined

GO{
    
    
	a:undefined;
}

3、将声明函数添加进GO对象呢,值为函数体

GO{
    
    
	a:undefined;
	function test() {
    
    }}

预编译完成,执行代码
第一条 控制台输出a,此时a的值为:undefined

第二条 a赋值,此时GO对象内的a值变为100

GO{
    
    
	a:100function test() {
    
    }}

第三条 执行函数test(),生成AO对象

AO{
    
    

}

第四条 将函数声明的变量添加进AO对象,值为undefined

AO{
    
    
	a:undefined;
}

(函数没有传递参数,跳过函数预编译的第三步)

(函数里面没有声明函数,跳过函数预编译的第四步)

第五条 执行函数,打印a,此时AO里面有属性a,则输出AO里面a的值,即输出: undefined

第六条 AO的a赋值200,此时AO的a的值为200

AO{
    
    
	a:200}

第七条 输出a的值:200

第八条 将300的值赋值给b再赋值给a,此时b未声明,所以b为全局变量,将b添加进GO对象内,将a的值改为300

GO{
    
    
	a:100function test() {
    
    };
	b:300}
AO{
    
    
	a:300}

第九条 输出a的值:300,函数执行完成

第十条 输出b的值:300

第十一条 输出a的值,此时a的值为GO里面的值:100

几道面试题

 function test(){
    
    
    console.log(b);//undefined
    	if(a){
    
    
    		var b =100;
    	}
    	console.log(b);//undefined
    	c =234;
    	console.log(c);//234
    }
    var a ;
    test();
    function bar(){
    
    
     	return foo;
     	function foo(){
    
    }
     	var foo =11;
    }
   console.log(bar());
 console.log(bar());
 function bar(){
    
    
 	foo=10;
 	function foo(){
    
    }
 	var foo=11;
 	return foo;
 }
var x = 1;
if( function f(){
    
    } ){
    
    
    x += typeof f;
    // console.log(f);
}
console.log(x);


// if的()将function f(){}变为一个表达式,是立即执行函数,执行结束后就销毁
// 所以x += typeof f; 中,f此时是无定义,若直接console.log(f)会报错:ReferenceError: f is not defined
// typeof(f)是唯一一种不报错并返回字符串"undefind",所以x为字符串"1undefined"

猜你喜欢

转载自blog.csdn.net/literarygirl/article/details/112863677
今日推荐