JavaScript(高级篇--function)

三种定义函数的方式:
function语句形式
函数直接量形式
通过Function构造函数形式定义函数
比较三种方式定义的区别:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Untitled Document</title>
        <script type=text/javascript charset=utf-8>
            
            // 3种方式定义函数 
            
            // 1 function语句式
            function test1(){
                alert('我是test1');
            }
            //test1();
            
            // 2函数的直接量 ECMAScript
            var test2 = function(){
                alert('我是test2');
            }
            //test2();
            
            // 3function构造函数式
            var test3 = new Function("a" , "b" ,"return a+b;");
            //alert(test3(10,20));
            
            
            
            //1.效率对比
            var d1 = new Date();
            var t1 = d1.getTime();
            for(var i =0 ; i <100000;i++){
                //function test1(){;}        //function语句的形式  15ms(只创建一次,后面重复的不再创建,静态特性)
                var test2 = new Function();    //1500ms(每次都重新创建,动态特性)
            }
            var d2 = new Date();
            var t2 = d2.getTime();
            alert(t2 -t1);             
        
            
            //2. 解析顺序问题 对于function语句式的函数,javascript解析器会优先的解释
            test1();  //有结果
            function test1(){
                alert('1111');
            }
            
            
            //alert(test2); //表示变量声明了 但是没有被赋值
            //test2();  //结果is not a function , 顺序解析
            var test2 = function(){
                alert('2222');
            }
            
            
            // 4 2 3 3 5 6  关键是理解function 优先解析,其余2种是顺序解析
            function f(){return 1;}                 // 函数1     
            alert(f());        //返回值为4 说明第1个函数被第4个函数覆盖    
            var f = new Function("return 2;");        // 函数2 
            alert(f());        //返回值为2 说明第4个函数被第2个函数覆盖
            var f = function(){return 3;}            // 函数3 
            alert(f());           //返回值为3 说明第2个函数被第3个函数覆盖    
            function f(){return 4;}                 // 函数4 
            alert(f());        //返回值为3 说明第4个函数被第3个函数覆盖
            var f = new Function("return 5");         // 函数5 
            alert(f());    //返回值为5 说明第3个函数被第5个函数覆盖    
            var f = function(){return 6 ;}            // 函数6 
            alert(f());        //返回值为6 说明第5个函数被第6个函数覆盖            
            
            
            
            //3. 函数作用域的概念
            var k = 1 ; 
            function t1(){
                var k = 2 ; //局部变量 k
                //function test(){return k ;}     //function语句  返回的是2
                var test = function(){ return k};    //函数直接量  返回的是2
//                var test = new Function('return k;');    // 构造函数的方式,顶级作用域,相当于在全局创建一个函数,所以返回的是1
                alert(test());
            }
            t1();            
            
            
            
            
            
        </script>
    </head>
    <body>
    </body>
</html>
View Code

 

函数的参数:arguments对象
      arguments是表示函数的实际参数(与形参无关)

callee函数(回调函数属性)
    arguments对象的秘密属性 callee属性:  他能返回arguments对象所属的函数的引用,这相当于在自己的内部调用自己。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Untitled Document</title>
        <script type=text/javascript charset=utf-8>
            
                    // function参数
                    
                    //形参列表
                    
                    //js中 函数的参数: 形参 实参
                    function test(a,b){
//                        alert(test.length);        //判断形参个数,不建议这样用  2个
                        //函数的实际参数 内部就是用一个数组去接受函数的实际参数
                        // arguments 对象 可以访问函数的实际参数
                        // arguments 对象 只能在函数的内部访问和使用 
//                        alert(arguments.length);
//                        alert(arguments[0]);
//                        alert(arguments[1]);
                        if(arguments.callee.length == arguments.length){
                            return a+b;
                        } else {
                            return '参数不正确!';
                        }
                        //arguments对象 用的最多的 还是做递归操作
                        //arguments.callee 指的就是函数本身,底层代码都是这种写法,不能写死
                    }
//                    alert(test(10,20));        // 30    
                    
                    
                    
                    function fact(num){
                             if(num <=1) return 1 ;
                             else  return num*arguments.callee(num-1);
                     }        
//                    alert(fact(5));    

                /*
                     function fact(num){
                             if(num <=1) return 1 ;
                             else  return num*fact(num-1);
                     }    
                    var F = fact ;  //复制函数
                    fact = null;    //在大型程序中调用方法,可能把原函数置空,这样就会报错,所以fact函数内部的调用本身不能写死
                    alert(F(5));        
                */
                    
        </script>
    </head>
    <body>
    </body>
</html>
View Code

 

this对象是在运行时基于函数的执行环境绑定的。在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。
也就是说this关键字总是指代调用者。

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Untitled Document</title>
        <script type=text/javascript charset=utf-8>
            
                    // this:this对象是指在运行时期基于执行环境所绑定的
                    // this总是指向调用者,也就是说 谁调用了我 我就指向谁
                    
                    var k = 10 ; 
                    function test(){
                          k = 20 ;
                    }
                    test();
                    alert(k);   //20, 函数内部对k再次赋值,覆盖了全局变量K的值,见下面的代码就明白了
                    
                /*
                    function test(){
                          this.k = 20 ;// this 指window
                    }
                    window.test();
                */    
        </script>
    </head>
    <body>
    </body>
</html>
View Code


每一个函数都包含两个非继承而来的方法:call、apply。 这俩个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Untitled Document</title>
        <script type=text/javascript charset=utf-8>
            
            //1.  call apply  简单的用法:绑定一些函数 用于传递参数 调用 
            
            function sum(x , y){
                return x+y;
            }
            function call1(num1 , num2){
                return sum.call(this , num1 , num2);  //把sum函数绑定到当前函数,并且传递参数
            }
            function apply1(num1 , num2){
                return sum.apply(this , [num1,num2]);//作用同上,只是参数写法不同
            }
            alert(call1(10 , 20));
            alert(apply1(20,40));
            
            
            
            //2. 扩充作用域,最大好处就是对象不需要与方法有任何耦合关系
            
            window.color = 'red';
            var obj = {color:'blue'};
            var obj2 = {color:'yellow'};
            function showColor(){
                alert(this.color);
            }
            
            showColor.call(window);  //red
            showColor.call(obj);  //blue
            
            
            
            
            //3.  call方法的简单模拟与实现
            
            //function 方法
            function test1(a , b){
                return a+b;
            }
            
            // 自定义的对象,JS约定函数首字母大写就是自定义对象
            function Obj(x, y){
                this.x = x ; 
                this.y = y ;
                return x*y;
            }
            
            var o = new Obj(10 , 20);
            // alert(test1.call(o,o.x ,o.y));   //对象Obj调用函数test1,可以使用外部的方法。
            
            o.method = test1 ;//给对象定义一个临时的方法,把外部的方法赋给他,效果一样
            alert(o.method(o.x , o.y));
            delete o.method;
            
        </script>
    </head>
    <body>
    </body>
</html>
View Code

 

执行环境(execution context)是javascript中最为重要的一个概念。执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每一个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们的代码无法访问这个对象,但是解析器在处理数据时会在后台执行它。
全局执行环境是最外围的一个执行环境。根据ECMScript实现所在的宿主环境不同,表示执行环境的对象也不一样。
每一个函数都有自己的执行环境。当执行流进一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返还给之前的执行环境。当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Untitled Document</title>
        <script type=text/javascript charset=utf-8>
            
            //1 执行环境 window对象(最上层的执行环境)
            
            var color1 = "blue";
            function changeColor(){ // 每一个函数 都有一个执行环境 (variable obj)
                var color2 = "red";
                function swapColor(){        // 这个函数 又产生了一个执行环境 (variable obj)
                
                    // c3 3级作用域  c2 2级作用域 c1 1级作用域
                    var color3 = color2; 
                    color2 = color1;
                    color1 = color3;
                    //这里可以访问:color1、2、3
                }
                
                //这里可以访问color1、color2、但不能访问color3
                swapColor();
            }
            //这里只能访问color1
            changeColor();         // 作用域 window  第一个作用环境    
            
            // 环境变量 可以一层一层的向上进行追溯 可以访问它的上级 环境(变量和函数) ----作用域链的概念
            // 一层一层的像上追溯--大型程序很少用全局变量,一层层找效率慢
            
        </script>
    </head>
    <body>
    </body>
</html>
View Code

 

垃圾收集、块级作用域

    <script type=text/javascript charset=utf-8>
            
            
            //垃圾收集 方法1 标记方法  2 引用计数法
            /*
            function test(){
                 var a = 10 ;     //被使用   
                 var b = 20 ;    //被使用
                 var c ;
            }
            test(); //执行完毕 之后 a、b又被标记了一次 :没有被使用
            */
            
            
            //块级作用域的概念
            
            //高级程序语言 java  for  if 块级作用域的概念、
            // js 没有块级作用域的概念, 所以i 在for循环执行完毕还没销毁,要等整个函数执行完毕才被回收
            function test(){
                for(var i = 1 ; i <=5; i++){  //i
                    alert(i);
                }
                alert(i);  //6
            }
            test();
            //alert(i);//这里就会报错
            
            
            // js : () 表示执行
            //模拟块级作用域的概念(function(){  })();, 函数执行完毕,i被回收了。
            function test(){
                (function(){
                    for(var i = 1 ; i <=5; i++){  //i
                        alert(i);
                    }                        
                })();
                alert(i);//i is not defined
            }
            test();
            
            
            (function(){  alert('我直接执行了!');  })();
            
        </script>
View Code

 

闭包:一个函数 可以访问另外一个函数作用域中的变量。 需要理解作用域链的概念

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Untitled Document</title>
        <script type=text/javascript charset=utf-8>
            
            
    
            var name = "xiao A";
            var obj = {
                  name : "xiao B" ,
                  getName: function(){
                    return function(){
                        return this.name;
                    }
                }
            };
            //alert(obj.getName()());    
            var k = obj.getName();  //全局作用域     function(){return this.name;}
            alert(typeof k); // function类型
            alert(k());    //xiao A, 因为window调用这个函数中,所以this 是window

            
            var name = "xiao A";
            var obj = {
                  name : "xiao B" ,
                  getName: function(){
                      // this总是指向调用者, obj 
                    var o = this;
                    return function(){
                        return o.name;
                    }
                }
            };
            //alert(obj.getName()());    
            var k = obj.getName();
            alert(k());   //xiao B 
    
            
            
            // 闭包:一个函数 可以访问另外一个函数作用域中的变量
            // 封闭性 : private 起到一个保护变量的作用
            //temp 不会被回收,因为被下面那个函数引用了。
            // 1 级作用域
            function f(x){        // 2 
                        var temp = x ;         //局部变量     //temp已经没有被使用    
                        return function(x){        // 3 (function 有了一个执行域 var obj)
                            temp += x ;        //  又被使用了                        
                            alert(temp);                        
                         }
            }                
            var a = f(50);//50 赋给了temp , 不会给下面的函数的参数X, 因为下面那个函数当做一个Obj返回了
            alert(a);//function(x){temp += x ;    alert(temp);}
            
            a(5); //55                
            a(10);//65
            a(20);    //85        
            
            

            
        </script>
    </head>
    <body>
    </body>
</html>
View Code

 

posted @ 2017-03-11 00:21  SKYisLimit  阅读(201)  评论(0)    收藏  举报