函数
1.定义:
函数声明:function theFirstName(){
}
函数声明中的函数名遵循小峰峰:第一个单词小写,后面单词首字母大写。
函数表达式: var demo = function(){
document.write (‘a’);
}
2.组成形式:
形参、实参
形式参数 -- 实参
function sum (a,b,c,d){
if(sum.length > arguments.length){
console.log('形参多了')
}else if(sum .length < arguments .length){
console.log(‘实参多了’)
}else {
console.log(‘相等’);
}
sum(11,2,3)
//实际参数 -- 实参
小练习:
1.写一个函数,功能是告知你所选定的小动物的叫声。
2.定义一组函数,输入数字,逆转并输出汉字行式
3.写一个函数,实现斐波那契数列
代码:
1.
<script type=”text/javascript”>
function sound(animal){
switch(animal){
case“dog”:
document.write(‘wang!’);
return;
case“cat”:
document.write(‘miao!’);
return;
case“fish”:
document.write(‘bolu!’);
return;
}
}
</script>
<script type=”text/javascript”>
function reverse(){
var num = window.prompt(‘input’);
var str = ‘’;
for(var i = num.length - 1; i >= 0; i --){
str += transfer(num[i]);
}
}
function transfer(target){
switch(target){
case“1”:
return“一”;
case“2”:
return“二”;
case“3”:
return“三”;
case“4”:
return“四”;
case“5”:
return“五”;
}
}
</script>
<script type = "text/javascript"> //递归
function mul(n){
if(n == 1 || n == 0){
return 1;
}
return n * mul(n-1);
}
</script>
3.<script type = "text/javascript">
function fb(n){
if(n == 1||n == 2){
return 1;
}
return fb(n-1)+fb(n-2);
}
</script>
js运行三部曲:
-
语法分析
-
预编译
-
解释执行
-
预编译:
1.函数声明整体提升(不管你在哪声明函数,系统总会将他提升到最前端)
2.变量 声明提升(对应例子2,声明变量的那一步会提升)
test();
function test(){
console.log(‘a’);
}//a
在定义之前执行函数仍可执行,体现预编译特点。
console.log(‘a’);
var a = 123;
//123
在声明之前仍可输出,体现预编译特点。
立即执行函数
-
定义:此类函数没有声明,在一次执行过后立即释放。适合做初始化。
-
针对初始化功能的函数
写法:1.(function(){}());—W3C建议使用
2.(function(){})(); -
只有表达式才能被执行符号执行
函数声明:
<script type = "text/javascript">
function test(){
var a = 123;
}();
//不可以执行
</script>
函数表达式:
<script type = "text/javascript">
var test = function(){
console.log('a');
}() //可以执行
</script>
<script type = "text/javascript">
function test(){
var a = 123;
}
test();//可以执行,此单独行是表达式
</script>
将声明变成表达式:
- “+”
“-”
"!"均算数学表达符
<script type = "text/javascript">
+(function test(){
console.log('a');
})(); //可以执行
</script>
- 括号算数学表达符,所以将一个函数声明放进括号就变成了函数表达式。
<script type = "text/javascript">
(function test(){
console.log('a');
})(); //可以执行,小括号放在里外都可以
</script>
能被执行符号执行的函数,在一次执行过后立即释放。
作用域
-
[[scope]]:
每个JavaScript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供JavaScript引擎存取,[[scope]]就是其中一个。
[[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合。 -
作用域链:[[scope]]:中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种接链式链叫做作用域链。
-
执行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象(AO)。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。
ps:为什么要区分出AO、GO:
GO保存全局里的所有元素,
AO保存一部分函数里面的所有元素,
当函数用完时,需要释放内存,如果没有AO,数据全部都在GO里,那么无法区分是否要释放(无法区分是否是部分函数的,如果是部分函数的,就可以直接释放了。)
- 查找变量 :从作用域的顶端依次向下查找(在哪个函数里面查找变量,就上哪个函数的作用域的顶端查找)。
例题:
根据以下这个函数分别写出a、b、c的作用域。
<script type = "text/javascript">
function a(){
function b(){
function c() {
}
c();
}
b();
}
a();
</script>
作用域:
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 : cAO
1 : bAO
2 : aAO
3 : GO
最终在最里层的函数串成了最完整的作用域链。
生成概括:里层的函数定义域链总是继承它的外层的,作用域链总是先生成自己的AO,再串之前的。
例题:
<script type = "text/javascript">
function a() {
function b() {
var bbb = 234 ;
console.log(aaa);
}
var aaa = 123;
return b;
}
var glob = 100;
var demo = a();
demo();
</script>
// 123
解题过程:
a执行:
a doing a.[[scope]] -- > 0 : aAO
1 : GO
b定义:
b defined b.[[scope]] -- > 0 : aAO
1 : GO
b doing b.[[scope]] -- > 0 : bAO
1 : aAO
2 : GO
解析:a执行完,里面的全部信息清除,表示为a --> 0AO的这条线断了,但是AO这个房间还在,b --> AO 这条线还在,而b被保存到了外部,表示b带着AO、GO出来,在外部执行,此时b会生成一个新的执行单文,串在b作用域链的顶端 ,此时b有0.1.2位。
执行demo()时,要打印console.log(aaa),在b的第零位0 : bAO没找到, 在b的第一位1 : aAO找到var aaa = 123。
但凡是内部的函数被保存到了外部,一定会生成闭包。
例题:
<script type = "text/javascript">
function a() {
var num = 100;
function b () {
num ++;
console.log(num);
}
return b;
}
var demo = a();
demo();
demo();
</script>
//101 102
解析:a执行完,里面的全部信息清除,表示为a --> 0AO的这条线断了,但是AO这个房间还在,b --> AO 这条线还在,而b被保存到了外部,表示b带着AO、GO出来,在外部执行,此时b会生成一个新的执行单文,串在b作用域链的顶端 ,每次执行b时,先在b的bAO(第零位)里面找,找不到再去a的AO(第一位)里面找,找不到再依次向下,直到找到为止。
并且每次执行b时,由上述过程依次调用,执行完毕后销毁bAO,下次再调用再生成一个新的bAO,串在作用链顶端。
第一次执行demo()时,在aAO的num上++
第二次执行demo()时,再次在aAO的num上++