1.5.6函数作用域
Posted aorange
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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: auto:function()
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)无法被垃圾回收机制回收,导致了内存泄漏
GO:outer: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(‘我被启动了‘);
)()
以上是关于1.5.6函数作用域的主要内容,如果未能解决你的问题,请参考以下文章