1.5.6函数作用域

1.5.6 函数作用域

1.作用域   定义变量并能找到变量的规则

在函数里面中可以使用全局变量在全局中不能够使用函数中的变量

             

js中 变量有两个存放的区域

1.全局作用域:

全局变量会自动成为window对象的属性

window对象也可以叫做Global Object GO对象

打开浏览器 自动生成window对象,即生成GO对象

关闭浏览器 window对象就自动销毁了

eg:当打开浏览器的时候,会自动生成GO对象,会自动把变量名生成GO对象的属性名,变量名的值会变成GO对象的属性值,上图的auto不在花括号内,所以是全局变量

函数表达式也可以放到全局变量中

GO {   属性名:属性值

c:'heaven',

auto:function(){},

heaven:function(){}

 }

 

2.函数作用域

函数的预编译四部曲:  /* 函数执行时,会生成一个AO对象,活动的*/

①创建AO对象 ==> Activated Object(活动对象)  

找到形参和变量,把形参和变量作为AO对象的属性名,值是undefined

把实参的值赋给形参。此时不再是undefined

④在函数中找到函数声明,把函数名作为AO对象的属性名,值是函数体。

预编译之后才能执行JS代码  函数执行后必然生成自己的AO对象,函数执行完后被销毁

全局的预编译三步:

1.创建GO对象 ==> Global Object(GO对象)

2.找到变量,把变量作为GO对象的属性名,值是undefined

3.在全局中找到函数声明,把函数名作为GO对象的属性名,值是函数体

开始执行代码

函数表达式也可以放到全局变量中

预编译练习:
function outer(){
/*
* AO{
* b:3,
* inner:function(){}
* }
* */
function inner(){
/*
* AO{
* a:4
* }
* */
var a = 4;
c = 5; //一个变量 没有var关键词,直接赋值,则这个是全局的,叫做暗示全局变量
console.log(a); //4 inner的AO中找到变量a
console.log(b); //3 outer的AO中找到变量b
console.log(c); //5 GO中找到变量c
}
var b = 3;
inner();
}
outer();
var a = 2;
console.log(outer);

找变量的时候,先找里面,再找外面

函数里面var a=4;先是走第二步,a:undefind,之后再变成a=3,打印的时候会从AO对象里面找

 

3.变量提升:预编译时,从上往下,第一句是打印,第二句是定义,则打印出是undefined var b 所以被提升   

 

 

4.作用域链

console.dir()下的函数的[[Scopes]]这个属性 存放在函数的作用域链

 

 

inner函数未执行(死函数)

--->inner函数的作用域链 = outer:AO+GO  (就是不算的时候)

 

inner() -->inner函数执行(激活的函数)

--->inner函数的作用域链 = inner:AO + outer:AO + GO 执行时)

 

所以a在当前的函数里面找不到,会顺着作用链找,就是从内部往上找

outer函数未执行

--->outer函数的作用域链 = GO  (outer所在的环境是GO)

outer()函数执行

--->outer函数的作用域链 = outer:AO + GO

 

例子

 

 GO: autofunction(){}

 

 AO:  b:undefined

 

  a:undefined     然后执行第四不步,找到函数声明

 

  b:function() {}    所以上面的b被覆盖了

 

所以b打印出来的是一个函数,往上找

 

GO
a:2
auto:function(){}
AO
a:undefined 没有实参不执行第三步骤
没有函数声明

var a =2
function auto(a){
if(typeof a){ //所以a是undefined 
console.log("海文"); //type(undefined)== "undefined"
}else{ //转换为布尔值是true
console.log("heaven");
}
var a;
}
auto();

 

5.闭包

当内部函数被保存在外部时,由于内部函数的作用域链上存在内部函数创建时的环境(即父级函数和祖先函数的AO对象,全局对象GO),导致内部函数可以顺着作用域链寻找变量,所以形成了闭包,同时内部函数的作用域链上(即父级函数和祖先函数的AO对象,全局对象GO)无法被垃圾回收机制回收,导致了内存泄漏

GOouter:function(){},

  result:function inner(){}

outer:AO b:4

    inner:function(){}

    inner:AO{    空   }

function outer(){

  var b = 3;

  function inner(){    //outer:AO +GO

  b++;

  console.log(b); //4 在outer的AO中找到的

}

  return inner;   //是有return抛出里面的未激活函数的这样子形式叫闭包结构

}

  var result = outer();

  console.log(result); //打印的是inner的函数体

  result(); //让抛出来的inner函数再次执行

还有 var result = outer(); 是被提升了到GO,系统先var result,属性值是undefined, 原来的就变成 result = outer() // 不会显示出来的

 

1.5.7.函数表达式和函数声明之间的转换

函数声明转换成函数表达式的方法

在函数声明前面加上  , ~ ,+, -,把函数声明整体放置在()

重要结论:

* 1.函数表达式的名字只能在自身作用域中使用 (是会把自身函数打印出来)

! function auto(){

console.log(auto);

}

(函数表达式是没有名字的,var a=function 这里不能有名字(){},如果有名字,打印auto(),会报错,因为系统默认会把auto干掉)

* 2.只有函数表达式后面紧跟()才能执行后面()里的是用来传实参的

例子:

(function auto(){

console.log('我被启动了');

})()

 

猜你喜欢

转载自www.cnblogs.com/aorange/p/11032158.html
今日推荐