JavaScript 函数、作用域

函数

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(1123//实际参数 -- 实参

小练习:
1.写一个函数,功能是告知你所选定的小动物的叫声。
2.定义一组函数,输入数字,逆转并输出汉字行式
3.写一个函数,实现斐波那契数列

代码:
1.

<script type=”text/javascript”>
function sound(animal){
switch(animal){
case“dog”:
document.write(‘wang!’);
returncase“cat”:
document.write(‘miao!’);
returncase“fish”:
document.write(‘bolu!’);
return;
}
}
</script>
<script type=”text/javascript”>
function reverse(){
var num = window.prompt(‘input’);
var str = ‘’;
forvar i = num.length - 1; i >= 0; i --){
 str += transfer(num[i];
}function transfer(target){
switch(target){
case1”:
return“一”;
case2”:
return“二”;
case3”:
return“三”;
case4”:
return“四”;
case5”:
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上++

发布了49 篇原创文章 · 获赞 30 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Reagan_/article/details/81258206