错误处理,匿名函数,闭包

  1. 错误处理
  2. Function对象
    重载(overload)
    作用域和作用域链
    闭包(closure)

  3. 错误处理: 程序出错的情况下保证程序不中断退出的机制

      如何错误处理: 
      try{
         可能出错的代码
      }catch(err){
         处理错误的代码
      }finally{
         无论是否出错,都要执行的代码
      }
var d=prompt("输入小数位数");
var n=123.456;
    try{
        console.log(n.toFixed(d));
    }catch(err){
        alert("小数位数无效");
        //alert(err.message);
    }finally{//释放资源
        d=null;
        n=null;
    }  
其中: err: 发生错误时的错误对象
      err.message: 封装了错误的信息
        err.name:错误的名字
      Error: 错误对象,在错误发生时自动创建的,封装错误信息的对象。
      6种: SyntaxError: 语法错误
           ReferenceError: 引用错误,找不到对象
           RangeError: 范围错误,参数超范围
           TypeError: 类型使用错误, 错误的使用了对象的属性或方法。
           URIError: URI错误
           EvalError: 错误的使用了Eval


强调:finally中一般编写释放资源的代码
      如果不需要释放资源,finally部分可省略

关于性能: 
问题: 放在try中的代码,即使不出错,执行效率也会降低
解决: 大多数try catch都可用if  else代替
 为什么: 1. if else执行效率高;
  var d=prompt("输入小数位数");
  var n=123.456;
if(!isNaN(d)&&0<=d&&d<=20){
        console.log(n.toFixed(d));
}else{
        alert("小数位数无效");
}
    //释放资源
    d=null;
    n=null;    
  1. 不创建错误对象,节约内存空间,但,要求程序员的错误处理经验丰富
    何时使用try catch:
    1.如果可提前预料到错误的原因,就用if else
    2.如果无法提前预料到错误的原因,就用try catch
    try中仅包裹可能出错的代码
    比如: 凡是用eval,都要错误处理

    关于try catch中的return:

 /*鄙视题*/
        1. finally中有return:如果出错,返回4
                              如果没出错,返回3
           finally中的return替换之前的return
        2. finally中没有return: 如果出错,返回3,n:4
                              如果没出错,返回2,n:3
            finally中的代码也永远执行,
             但在确定return的值之后才执行
               finally执行后,才return
               finally的代码不会影响return的结果*/

            var n=1;
            function fun(){
                try{
                    //n++;
                    m++;//报错
                    return n; 
                }catch(err){
                    n++; 
                    return n;
                }finally{
                    n++; 
                    //return n;
                }
            }
            alert(fun());//2
            alert(n);//3 
     主动抛出错误: 
      何时抛出: 想提示别人错误的使用了自己定义的方法时
      如何抛出自定义:
      函数定义者抛出异常: throw new Error("错误信息")
函数调用者,需要用try catch接住抛出的异常,并处理
//程序员甲,函数定义者
function round(num,d){//函数定义者抛出自定义错误
        if(isNaN(num)||isNaN(d)){
            throw new Error("num 和 d 必须是数字");
            //抛出自定义错误,等效于错误
            //后续代码不再执行!
        }
        return Math.round(num*Math.pow(10,d))/Math.pow(10,d);
    }
    //程序员乙,函数调用者
    var num=prompt("输入数字");
    var d=prompt("输入小数位数");
    try{//函数调用者接住错误,并显示错误信息
        alert(round(num,d));
    }catch(err){
        //alert(err.message);
        alert("必须输入数字!");
    }
<script>
          function myFunction(){
                    try{
          var x=document.getElementById("demo").value;
          if(x=="")    throw "empty";
          if(isNaN(x)) throw "not a number";
          if(x>10)     throw "too high";
          if(x<5)      throw "too low";
                        }catch(err){
          var y=document.getElementById("mess");
          y.innerHTML="Error: " + err + ".";}
                            }
</script>

<h1>My First JavaScript</h1>
<p>Please input a number between 5 and 10:</p>
<input id="demo" type="text">
<button type="button" onclick="myFunction()">Test Input</button>
<p id="mess"></p>   
  1. Function:专门封装函数定义的对象
    重载(overload):相同函数名,不同参数列表的多个函数,在调用时,可根据传入参数的不同,自动挑选对应的函数执行。
    为什么: 节省调用使用API的负担
    强调: 没有代码重用!
    何时使用: 同一件事,不同参数,决定不同的业务流程

    js语法不支持重载: js中两个同名的函数,后定义的会覆盖先定义的。仅有一个生效。
    解决:函数中的arguments对象
    arguments对象:在函数作用域内,接收所有参数值的类数组对象——长得像数组的对象
    内容: 所有传入的参数值
    存储: 像数组一样存储:

  2. 下标访问每个参数值: arguments[i]

  3. 也有length属性,记录参数个数

    参数 vs arguments:

    参数:
    1. 提示调用者,如何传入数据
    2. 在函数内使用时,见文知意
    以参数为主
    arguments:
    1. 在模拟重载时
    2. 在不确定参数个数时
    特殊情况才用arguments

    在普通模式中: 参数中和arguments中使用同一个值
    一方修改,另一方同时变化——不合理
    解决: 严格模式: 在函数内,顶部加:”use strict”;
    参数变量的值和arguments无关!

类数组对象 vs []:
相同: 1. 都可用[i]访问每个元素
2. 都有length属性记录元素个数
3. 都可用for循环遍历,尽量不要用for in遍历

  不同点: 1. 类型不同: 
            [] 是 Array类型
            类数组对象 是 Object类型
             2. 类数组对象无法使用数组API
function checkout(){
        //arguments:[0:450].length:1
       //arguments:[0:"1010 1010 1010 1010",1:"123456"].length:2

        //如果传入一个参数,就现金结账
        if(arguments.length==1){
            console.log("现金结账");
            console.log("计算找零");
        }else if(arguments.length==2){
        //否则,如果传入2个参数,就刷卡结账
            console.log("刷卡");
            console.log("输密码");
            console.log("签字"); 
        }
    }
    checkout(450);
    checkout("1010 1010 1010 1010","123456");

    function calc(){
        //如果传入两个参数,就返回两值的和
        if(arguments.length==2){
            return arguments[0]+arguments[1];
        }else if(arguments.length==1){
        //否则 如果传入一个参数,就返回传入值的平方
            return arguments[0]*arguments[0];
        }
    }
    console.log(calc(12,35));//47
    console.log(calc(13));//169
  1. Function
    创建: 3种:
    1. 声明:
      function 函数名(参数列表){函数体;return 返回值}
      比如: function compare(a,b){return a-b;}
      只有声明方式创建的函数,才能被声明提前
    2. 直接量:
      var 函数名=function(参数列表){函数体;return 返回值}
      函数其实就是一个对象,函数名就是引用函数对象的变量
      还说明js中的函数,也可作为参数传递给方法或其他变量
      强调: 不能被声明提前
    3. 实例化对象:
      var 函数名=new Function(“a”,”b”,”return a-b”);

*匿名函数:
定义时没有其他变量引用的函数
特点: 定义后立刻调用,调用后立刻释放
为什么: 调用后立刻释放,节约内存
何时使用:
1. 自调: 定义完。立刻调用!
如何自调:
var 返回值=(function(参数列表){
函数体;
return 返回值
})(参数值列表)
何时使用: 如果完成一项特定任务的代码段,仅执行一次,就要用匿名函数封装!
强调: (参数值列表)可写在括号内
var r=(function(a,b){return a+b;}(12,35));
console.log(r);

2. 回调: 将函数交给其他方法去调用
       比如: arr.sort(function(a,b){return a-b});
       何时使用:如果其它函数需要一个函数作为参数时,而执行完希望立刻释放参数时,就用匿名函数作为参数。

作用域和作用域链:
作用域: 一个变量的可用范围
变量的存储位置
js:2种:
全局作用域window: 全局变量, 可反复使用,随处可访问
问题: 容易被污染
比如: 给从未声明过的变量赋值时,都会在全局创建或修改同名变量。
为什么: 凡是无主的变量或函数都是window的
比如: m=12; //假设m未声明
相当于window.m=12
函数作用域: 局部变量
存储在活动对象中,随函数调用而创建,调用后自动释放。
问题: 不可重用!

  作用域链: 从当前函数的作用域AO开始,逐级继承,直到window,形成的链      式关系。
  在函数中查找变量,按照从AO到window的顺序查找
   如果AO有,就不用window的
      如果AO没有,才去window找

 vs Java作用域:
   块级作用域: 
比如一个分支或循环结构,也是一级作用域
    Java中: 
       for(var i=1,sum=0;i<=100;sum++,i++);
       输出sum,报错!
       if(){var n}
       try{var m}catch(err){...}
       一旦结构执行完,n和m都不能用
    js中:没有块级作用域
       以上三种情况的变量都是在window中创建,
       可重复使用。

闭包:
保护一个可重用的局部变量的词法结构
为什么: 全局变量: 可重用,但易被污染
局部变量: 不可重用,
何时使用: 即可重用,又不会被污染
如何创建闭包:
1. 外层函数封装受保护的变量以及专门操作变量的内层函数
2. 外层函数将操作变量的内层函数返回到外部
3. 调用外层函数,获得内层函数的对象。

鄙视时:
1. 找受保护的变量
2. 同一次外层函数调用返回的内层函数,始终使用同一个受保护的局部变量
3. 每调用一次外层函数,就会多创建一个受保护的变量的副本。

函数的中的变量预处理以及执行处理:

(1)关于函数内的变量情况一

document.write(b);//全局预处理结果为undefined 声明提前,值在原地
            var b=3
            document.write(b);//全局预处理值为3
            function f(){//定义一个函数来改变b的值
                var b=10;//因为已在前声明b的值为3,所以该处的赋值不对b产生影响所以b任然等于3
            }
            document.write(b);//在调用函数前值为3
            f();
            document.write(b);//因为已在前声明b的值为3,所以该处的赋值不对b产生影响所以b任然为旧值等于3

(2)关于函数内的变量情况二

document.write(b);//全局预处理结果为undefined 因为声明提前,值在原地

var b=3
document.write(b);//全局预处理值为3
function f(){//定义一个函数来改变b的值
b=10;//此处为给b重新赋值,所以在调用该函数后,b的值为新值,也就是10
            }
            document.write(b);//在调用函数前值为3
            f();
            document.write(b);//b=10 因为在调用该函数后,b的值为新值,也就是10

(3)关于调用函数的全局预处理及执行处理
1.声明
function 函数名(参数列表){函数体;return 返回值}
比如: function compare(a,b){return a-b;}
只有声明方式创建的函数,才能被声明提前
document.write(f);//值为4 以function 函数名(){}方式的函数在全局预处理中可以直接调用(也就是在函数前也可调用),因为 document.write(f)的结果为函数f的字符串内容function f(a) {return a+1;}//
function f(a){return a+1;}

        f(9);
        document.write(f(9));//值为10  正常调用函数f后的新值。

2.直接量:
var 函数名=function(参数列表){函数体;return 返回值}
函数其实就是一个对象,函数名就是引用函数对象的变量
还说明js中的函数,也可作为参数传递给方法或其他变量
强调: 不能被声明提前

document.write("<br/>")
            //document.write(g(3));//会报错,因为此处是在函数g之前调用,
            //      所以以var 函数名=function(参数){}方式的函数在全局
            //      预处理中值为undefined,所以调用结果会报错。
            var g=function(b){
                return b+2
            }
            document.write(g(3));//5 正常调用函数
          var a=1,b=2;
            function add(a,b){

                var a=5;
                var b=10;
                c=a+b;
                return c;
            }
            alert(add(a,b));//15
            alert(c)//15 因为c未在函数内(局部)声明则为全局的变量
            alert(a)//1
            alert(b)//2


          var a=1,b=2;
            function add(a,b){
                c=a+b;
                var a=5;
                var b=10;

                return c;
            }
            alert(add(a,b));//3

            alert(c)//3 因为c未在函数内(局部)声明则为全局的变量
            alert(a)//1
            alert(b)//2
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值