(二)Javascript从函数至闭包
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了(二)Javascript从函数至闭包,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含8014字,纯文字阅读大概需要12分钟。
内容图文
![(二)Javascript从函数至闭包](/upload/InfoBanner/zyjiaocheng/599/8759fa384b894bc289f8c668d8f21b55.jpg)
(二)Javascript从函数至闭包初识
函数(也是一个引用值)
定义
? 函数出生的原因在于编程思想:高内聚,低耦合)
-
函数声明
//函数声明 function theFirstName(){ } //命明中第一个单词小写,之后的单词首字母大写(开发规范) .document.write(theFirsrName); //这里与C不同之处在于它不输出地址,输出的是函数体 //这里得到的是function theFirstName(){}
-
函数表达式
-
命明函数表达式
var test = function abc(){ document.write("a"); } //成为表达式,表示式实际上是忽略名字的 /*在console中输入test,出现的结果是函数体 function abc(){ document.write("a"); } 在console中输入abc,会显示没有被定义 在页面中输入test较为麻烦,需要document.write(test); */
-
匿名函数表达式----(函数表达式)
var demo = function(){ } /*小区别: test.name 得到的值为 abc demo.name 得到的值为 demo */
-
组成形式
-
函数名称
-
function test(a,b){ //相当于声明了a和b document.write(a + b); } test(1,2);
-
-
参数
-
形参
-
实参
-
形参和实参的映射规则
-
/* 形式参数为a,b 实际参数为1,2 形参的数目和实参的数目不需要一一对应 形参多时:多出来的设置为undefined 实参多时:形参有n个,把前n个实参传给形参 */ function sum(a,b,c,d){ //arguments -- [11,undefined,2,3,"abc"] 实参列表 if(sum.length > arguments.length){ console.log("形参多!"); } else if(sum.length < arguments.length){ console.log("实参多!"); } else { console.log("相等!") } } sum(11,undefined,2,3,"abc"); //一个求和函数 var result = 0; function sum(){ for(i=0;i<arguments.length;i++){ result += arguments[i]; } console.log(result); } sum(1,2,3,4,5,6,7,8,9); //打印出45 //映射规则 function sum(a,b){ a = 2; argument[0] = 3; console.log(a); //这里得到3.这里是argument变,a也跟着变,a变,argument也变,但两者表示的是相同的值 return; //return的作用与C语言相同——1.中止并有值返回值 } sum(1,2);
-
-
-
返回值
- 与C语言reture大致相同,可以终止函数并返回值。
作用域初探
- 作用域定义:变量(变量作用于又称上下文)和函数生效(能被访问的区域)
- 全局、局部变量
- 作用域的访问顺序
递归函数实现的 两点
找规律
找出口
(需要拿已知条件找出口)
JS运行三部曲
语法分析
-
javascript是一门解释性语言,解释一行执行一行
-
语法分析的过程:通篇扫描一遍,检查是否有语法错误
预编译
-
test(); function test(){ document.write("a"); } //由于预编译的存在,第一行代码可以执行 console.log(a); var a = 123; //这里得到的结果是undefined //这里如果将第8行代码去掉,会报错,因为a未声明 //总结:函数声明整体提升。变量仅声明提升。 //当然此处这是抽象概念
-
预编译前奏
-
imply global暗示全局变量:即任何变量,如果变量未经声明就赋值,此变量就为windows所有。
eg: a = 123;
eg: var a = b = 123;
function test(){ var a = b = 123; } test(); /* 1.首先要明白赋值是自右向左的 2.b未经声明就赋值,此时b为window所有,即window.b为123,在函数外可以调用b 3.a是在函数内部声明的,在外部调用会显示undefined */ function test(){ var b = 123; } test(); console.log(window.b); //此处的b属于局部声明,不会归于window所有
-
一切声明的全局变量,全是window的属性
- eg:var a = 123; ===> window.a = 123;
//经过声明后的变量,window就是全局的域 var a = 123; console.log(a); /* 这里需要从上一域去取a 此处全局声明a为123,则有 window{ a : 123 } 在全局中访问a的时候 console.log(a) --> console.log(window.a) */
-
预编译四部曲
-
创建AO对象。即Activation Object(执行期上下文)
-
找形参和变量声明(此处就是变量声明提升的过程),将变量和形参名作为AO属性名,值为undefined
-
将形参和实参统一
-
在函数体里找函数声明(此处就是函数声明提升的过程),值赋予函数体
- 典例
//预编译发生在函数执行的前一刻 function fu(a){ console.log(a); var a = 123; console.log(a); function a(){} console.log(a); var b = function(){ console.log(b); function d(){} } } fu(1) /* 过程 1.创建AO对象 AO{ } 2.提升过程 AO{ a : undefined, //a出现了两次,但是只挂一次 b : undefined } 3. AO{ a : 1, b : undefined } 4. AO{ b : undefined, //函数声明有a和d,把这两个挂起来,值赋予函数体,得到 a : function a(){}, d : function d(){} //第四步优先级最高,a的值1被函数体覆盖 } */ //之后利用AO对象来执行 /* 在执行过程中一行一行执行,赋值就是在执行中进行。 所以上面得到的结果是 function a(){} 123 123 function(){} */ function test(a,b){ console.log(a);//function a(){} console.log(b);//undefined var b = 234; console.log(b);//234 a = 123; console.log(a);//123 function a(){} var a; b = 234; var b = function(){} console.log(a);//123 console.log(b);//function(){} } test(1); /* 预编译后的AO为: AO{ a : function a(){}, b : undefined }
需要特别注意的是:声明并赋值,赋值只会在执行时候一行一行下来才会进行
- 关于全局的预编译:
不只是函数,全局中也会进行预编译过程,全局的预编译缺少一个形参实参统一的步骤,它生成的是GO对象(GO === window)
function test(){ var a = b = 123; console.log(window.b); console.log(window.a); } test(); //注意这里b未经声明就赋值发生了 imply global,b到了GO中预编译的 // 这里输出的结果是123和undefined
-
解释执行
-
练习:
<script type="text/javascript"> console.log(test); function test(test){ console.log(test); var test = 234; console.log(test); function test(){ } } test(1); var test = 123; </script> /* 按步骤来 首先是在script中进行预编译 GO{ test = undefined ---> function test(){}; } 之后开始执行 第3行显示function test(test){......} 第4~10行是预编译处理过的函数,略过 第11行开始调用函数,进行函数的预编译 AO{ test : undefined ---> 1 ---> function test(){} } 之后开始执行函数 第5行:显示 function test(){} 第6行:赋值起效 第7行:显示234 第8行:预编译处理的函数,略过 第12行:赋值window.test=123起效 所以最后结果显示: function test(test){ console.log(test); var test = 234; console.log(test); function test(){ } } function test(){} 234 */
两道百度笔试题
1. function bar(){ return foo; foo = 10; function foo(){ } var foo = 11; } console.log(bar()); 2. console.log(bar()); function bar(){ foo = 10; function foo(){ } var foo = 11; return foo; } //注意console控制台显示的应该是bar(),即函数返回值,如果console括号里面是barm,则返回的是函数体 1.答案:function foo(){} 2.答案:11
作用域精解
-
[[scope]]:每个javascript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些不可以用的属性仅供javascript引擎存取,[[scope]]就是其中一个。
定义:[[scope]]指的是我们所说的作用域,它是一个隐式的属性,其中存储了运行期上下文的集合。
- 作用域是由函数产生,一切对象都有属性,函数也是一种对象,它是一种特殊类属性,比如我们可以访问它的test.name,test.[[scope]]
-
运行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象(即AO)。一个执行器上下文定义了一个函数执行时的环境(即变量提升的过程),函数每次执行时对应的上下文都是独一无二的(第一次调用函数时产生的AO与第二次调用时产生的不同),所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁
-
作用域链:[[scope]]中所存储的执行器上下文对象的集合,这个集合呈链式连接,我们把这种链式连接叫做作用域链
function a(){
}
var glob = 100;
a();
/*
a函数被定义的时候,a.[[scope]] 里面存了一个作用域链,这是作用域链还没达到集合的程度,只有一个第0位,而第0位指向的是GO
a执行的时候,它产生自己的一个AO,AO会被放在作用域链的顶端。
也就是说被定义时 a.[[scope]]--> 0:G0{}
在执行a();的时候 a.[[scope]]--> 0:AO{}
1:GO{}
- 查找变量:在哪个函数中查找就从哪个函数的作用域链中依次向下查找。
function a(){
function b(){
var bb = 234;
aa = 0;
/*此处执行的时候b在作用域链头开始找,第0位的AO中无aa,第一位中的AO(即函数a的AO)中含有aa,所以赋给aa的值变为0 */
}
var aa = 123;
b();
console.log(aa);
//结果是 0
}
var glob = 100;
a();
//在b函数执行完后,b的AO被销毁,b的作用域链变为原来b刚被定义的时候,b执行完后紧接着a函数也执行完了,a函数的作用域链回到第0位为GO的状态
function a(){
function b(){
function c(){
}
c();
}
b();
}
a();
/* 过程如下:
a defined a.[[scope]] --> 0:GO
a doing a.[[scope]] --> 0:aAO
1:GO
b defined b.[[scope]] --> 0:aAO
1:GO
b doing b.[[scope]] --> 0:bAO
1:aAO
2.GO
c defined c.[[scope]] --> 0:bAO
1:aAO
2:GO
c doing c.[[scope]] --> 0:cA0
1:bAO
2:aAO
3:GO
典例:
function a(){
function b(){
var bbb = 234;
document.write(aaa);
}
var aaa = 123;
return b ;
}
var glob = 100;
var demo = a();
demo();
//此处在a函数执行到第6 7行代码时,第6行给aAO中的aaa从undefined变为123,第7行将b函数保存出来,此时b函数是被定义的状态,他的作用域链第0位为aAO,第一位为GO,到了第8行,函数a结束,a变为a刚定义的状态,切断了与aAO的联系,但aAO这个房间还是存在。b函数赋给了demo,执行函数demo,此时demo的作用域链第0位为demoAO,第1位为aAO,第二位为GO
闭包初识
? 简单概述:但凡是内部的函数被保存到了外部,它一定生成了闭包。即内部函数保存了外部函数的劳动成果,即函数a的房间即使切断了也删除不了,因为b始终攥着a的房间
? 小例子:
function a(){
var num = 100;
function b(){
num++;
console.log(num);
}
return b;
}
var demo = a();
demo();
demo();
//得到结果是101和102
内容总结
以上是互联网集市为您收集整理的(二)Javascript从函数至闭包全部内容,希望文章能够帮你解决(二)Javascript从函数至闭包所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。