本内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。

函数的形参和实参:

参数有形参(parameter)和实参(argument)的区别,形参相当于函数中定义的变量,实参是在运行时的函数调用时传入的参数。

ECMAScript函数的参数与大多数其他语言中函数的参数有所不同。ECMAScript中的函数定义并未指定函数形参的类型,函数调用也未对传入的实参值做任何类型检查,甚至不检查传入形参的个数;也就是说,即便定义的函数只接收两个参数,在调用 这个函数时也未必一定要传递两个参数,可以传递一个、三个甚至不传递;在实际场景中,需要处理当调用函数时的实参个数和声明的形参个数不匹配的情况,也会测试函数的实参的类型,以避免非法的实参传入函数;

可选形参:

当实参比形参的个数要少时,剩下的形参都将设置为undefined值;为了让实参与形参保持较好的适应性,有必要为可选形参设置一个合理的默认值;如:

function show(name,msg){    console.log("hello," + name + ",message: " + msg);}show(); // hello,undefined,message: undefinedshow("wangwe");  // hello,wangwe,message: undefinedshow("wangwei","18 year old");  // hello,wangwei,message: 18 year old// show函数改成function show(name,msg){    if(name == undefined) name = "wujing";    if(msg == undefined) msg = "28 girl";    console.log("hello," + name + ",message: " + msg);}// 不使用if,可以使用“||”,这是种惯用手法function show(name,msg){    name = name || "wujing";    msg = msg || "28 girl";    console.log("hello," + name + ",message: " + msg);}

又如:

// 将对象o中可枚举的属性名追加至数组a中,并返回这个数组a// 如果省略a,则创建一个新数组并返回这个新数组function getPropertyNames(o, /* optional */ a){    if(a == undefined) a = []; // 如果未定义,则创建新数组    //a = a || [];  // 使用||运算符    for(var property in o) a.push(property);    return a;}// 使用,先创建一个对象var o = {name:"wangwei",age:18,sex:"男"};// 调用这个函数可以传入1或2个参数var arr = [1,2];// var arrPropertys = getPropertyNames(o);  // 使用一个参数var arrPropertys = getPropertyNames(o,arr);  // 使用两个参数console.log(arrPropertys);

说明:当设置可选参数时,一定要把可选参数放到形参列表的最后,因为不能省略第一个参数(定参)并传入第二个实参;如果第一个参数(定参)不存在或不使用,也需要显式的传入undefined,真实的场景是传入一个无意义的占位符null;

形参个数:

函数本身的length属性,只读,它代表函数的形参个数,即函数期望传入的实参个数,如:

function sum(a,b,c){  console.log(sum.length);  // 3}sum();console.log(sum.length);  // 3

实参对象(arguments):

ES函数的参数有自己独特的特点,即当调用函数时传入的实参个数超过函数定义的形参个数时,没有办法直接获得超出的实参的值,但可以使用实参对象arguments来获取;

在函数体内,arguments是指向实参对象有的引用,其是一个类数组对象(应该是一个集合);函数接收的始终都是这个数组,而不关心数组中包含哪些参数;即使没有传递参数,这个数组也存在,只不过是包含0个元素的数组;

function func(a,b){    console.log(arguments);}func();func(1,2,3,4,5);

arguments对象只是与数组类似,它并不是Array的实例;可以使用方括号语法访问它的每一个元素(即第一个元素是arguments[0],第二个元素是arguments[1],以此类推),使用length属性来确定传递进来多少个参数,即length属性说明调用函数时实际传递的参数个数;;

如,不显式地使用命名参数:

function sayHi(){    console.log("传入了:" + arguments.length + "个参数");    console.log("Hello,"+arguments[0]+","+arguments[1]);}//sayHi();sayHi("wangwei","欢迎你来学习");

说明:在ECMAScript中,命名的参数只提供便利,但不是必需的;另外,在命名参数方面,其他语言可能需要事先创建一个函数签名,而将来的调用必须与该签名一致;但在ECMAScript中,没有这些规定,解析器不会验证命名参数,因此可以使用arguments对象来验证所传递的参数是否符合函数要求;如:

// 实际场景中,如果对实参的个数有要求,需要进行验证function func(x,y,z){    // 首先,验证传入实参的个数是否正确    if(arguments.length != 3){        throw new Error("函数func需要:" + arguments.length + "个参数");    }    // 再执行函数的其他逻辑    if(typeof arguments[0] !== "number"){        console.log("参数类型应为数字")    }    y = +arguments[1] ? y : 0;     return x + y + z;}console.log(func(1,"a",3));  // 4

说明:在某些时候,没有必要检查实参的个数,因为JS的默认行为是可以满足需要的,如省略的实参都是undefined,多出的参数自动省略。

验证形参与实参的个数,如:

function check(args){    var actual = args.length;  // 实参的真实个数    var expected = args.callee.length;  // 形参个数    if(actual !== expected)        throw Error("参数个数不对");}function f(x,y,z){  try{    check(arguments);    return x + y + z;  }  catch(e){    console.log(e);  }}console.log(f(1,2,3));

可以利用arguments对象,让函数能够接收任意个数并分别实现适当的功能,如:

function doAdd(){    if(arguments.length==1){        console.log(arguments[0]);    }else if(arguments.length==2){        console.log(arguments[0]+arguments[1]);    }}doAdd(10);doAdd(10,20);// 优化function doAdd(){    var sum = 0;    for(var i=0;i

又如:

// 根据实参,返回最大值function max(/* ... */){    var max = Number.NEGATIVE_INFINITY;    for(var i = 0; i max) max = arguments[i];    return max;}var largest = max(1,10,100,2,3,1000,4,5,10000,6);console.log(largest);  // 10000

类似于这种可以接收任意个数的实参,这种函数也被称为“不定实参函数”,这个术语来自C语言。

但真正的不定实参的个数不能为零,其应用的场景是:该函数包含固定个数的命名和必须的参数,以及随后个数不定的可选实参,即arguments对象可以与命名参数一起使用;

function doAdd(num1,num2){   var result = parseInt(num1) + parseInt(num2);   if(arguments.length > 2){       for(var i = 2; i

arguments并不是真正的数组,它是一个对象,其数组元素是函数实参的别名;arguments的值永远与对应命名参数的值保持同步;

function func(num1){    // "use strict";  // 重写arguments的值会失效    console.log(num1);  // 10    arguments[0] = 1;    console.log(num1);  // 1}func(10);

说明:这并不是说读取这两个值会访问相同的内存空间,它们的内存空间是独立的,但它们的值会同步;即两者本质上是不同的,其使用的是映射的关系;

注:在严格模式下,重写arguments的值会失效,但不会导致语法错误;

实参类型:

Javascript是一门弱类型语言,所以函数中的形参并没有类型声明,并且在传入参数前也未做任何类型检查,虽然JS可以进行数据类型的自动转换,但在某些时候(类型不同,不会导致语法错误,但在程序运行时有可能导致错误),函数还是希望得到一个类型明确的参数值,此时,应当对所传入的参数进行类型的检查,如:

// 返回数组元素的累加和// 数组元素必须为数字,null和undefined的元素将被忽略function sum(arr){    if(Array.isArray(arr)){        var total = 0;        for(var i=0;i

又如:扩大累加的数据类型:

function flexsum(a){    var total = 0;    for(var i = 0; i

没有重载:

ECMAScript函数不能像传统意义上那样实现重载;而在其他语言中,可以为一个函数编写两个定义,只要这两个定义的签名(参数的类型和数量)不同即可;ECMAScript函数没有签名,因为其参数是由包含零或多个值的数组来表示的;而没有函数签名,真正的重载是不可能做到的;

如果定义了两个名字相同的函数,则只有后定义的有效,如:

function show(){alert("ok")};function show(){alert("wangwei")};show();

说明:即是第二个把第一个覆盖了;

var addNum = function(num){return num + 100;};addNum = function(num){return num + 200;};

模拟重载:可以通过检查传入函数中参数的类型和数量并作出不同的反应,可以模拟方法的重载;

function overrideFunc(){    var argLen = arguments.length;  // 可以传入整型,字符串    if(argLen == 0){        console.log("无参的overrideFunc()方法");    }else if(argLen == 1){        console.log("传入的参数为:" + arguments[0]);    }else if(argLen == 2){        console.log("传入了2个参数:");        if(!isNaN(arguments[0]) && !isNaN(arguments[1])){            console.log("和为:" + (arguments[0] + arguments[1]));        }else{            console.log("不是数字:" + arguments[0] + arguments[1]);        }    }else{        console.log("未知,其他处理,也可以抛出异常");    }}overrideFunc();overrideFunc("零点程序员");overrideFunc(3,4);overrideFunc(3,"a",33);

callee和caller属性:

arguments对象除了拥有数组元素外,还定义了callee和caller属性;

callee属性指向当前正在执行的函数,在某些时候非常有用,如在一个匿名函数中使用递归;但在严格模式下会抛出错误,所以,尽量避免使用callee属性,可以为函数明确定义一个名称;

function func(num1){    // "use strict";    console.log(arguments.callee);}func(10);// 递归函数function factorial(x){    if(x <= 1) return 1;    // return x * factorial(x - 1);    return x * arguments.callee(x - 1);}console.log(factorial(4));// 或在匿名函数中使用function create(){    return function(n){        if(n <= 1) return 1;        return n * arguments.callee(n - 1);    };}console.log(create()(4));

caller是非标准的,但大多数浏览器都实现了这个属性,它指向调用当前函数的函数,在ES5中被移弃了,其始终会返回undefined,不会报错。

将对象用做实参:

可以采用将对象作为实参,该对象的属性就是实际需要的实参值,并且参数的顺序就无关紧要了,而且还可以方便的设置缺省参数的默认值;作为实参的对象,一般采用键/值对的方式进行定义;如:

function copyArr(args){    var j = 0;    args.from = args.from || [ ];    args.start = args.start || 0;    args.to = args.to || [];    args.end = args.end || args.from.length;    for(var i = args.start; i

此种方式是一种惯用手法,特别是在一些框架插件中,经常使用这种方式来配置运行参数;如:videojs;

函数回调:

回调 :将一个函数对象a 传递给另一个函数对象 b,让后者在适当的时候执行 a。这就是所谓的“回调”

适当的时候:当这个外部函数在一定条件下就会调用参数指定的函数,此函数就是回调函数。如:

function funA(){    // 代码}function funB(fun){    fun();}funB(funA);function fun(num,callback){    if(num<0){        alert("分数不能为负");    }else if(num==0){        alert("可能未参加考试");    }else{        callback();    }}function test(){    var myp = document.getElementById("myp");    var str;    var score = document.getElementById("score").value;    fun(score, function(){        if(score<60){            str = "不及格";        }else if(score>=60 && score<80){            str = "及格";        }else{            str = "优秀";        }        myp.innerText = str;    });}
function sortNum(obj,fun){    if(!(obj instanceof Array) || !(fun instanceof Function)){        throw "调用错误";    }    for(n in obj){          // 开始排序        for(m in obj){            if(fun(obj[n], obj[m])){    // 使用回调函数排序,规则由用户设定                var tmp = obj[n];                obj[n] = obj[m];        // 交换数据                obj[m] = tmp;            }        }    }    return obj; // 返回排序后的数组}function compare(num1,num2){    // 回调函数,自定义排序规则    return num1 > num2;     // 由大到小}try{    var numArr = [5,68,32,1,45,7,25];    console.log("排序前:" + numArr);    sortNum(numArr,compare);    console.log("排序后:"+ numArr);}catch(e){    alert(e);}

匿名函数:

匿名函数即为没有名字的函数,也称为拉姆达函数;匿名函数功能强大,用途很广;

形式:function(arg0,arg1){} // 其实函数表达式使用的就是匿名函数

一般将匿名函数作为参数传入另一个函数,或者从一个函数中返回另一个函数,这是一种极为有用的技术;如:

function createFun(propertyName){    return function(object1,object2){        var value1=object1[propertyName];        var value2=object2[propertyName];        if(value1 value2){            return 1;        }else{            return 0;        }    }   }var arr=[{name:"zhangsan",age:28}, {name:"lishi", age:29}];arr.sort(createFun("name"));alert(arr[0].name);arr.sort(createFun("age"));alert(arr[0].name);

说明:实质上就是嵌套了一个内部函数,并把它返回;这是一个比较函数;

作为值的函数:

在ES中函数不仅是一种语法,也是值;因为其本身就是变量,所以函数也可以作为值来使用;也就是说,可以将函数赋值给变量、存储在对象的属性或数组元素中,也可以当作一个参数进行传递;

函数可以赋值给其他的变量,如:

function func(x){return x * x};var s = func;console.log(func(4));  // 16console.log(s(4));  // 16

同样可以将函数赋值给对象的属性,此时应该称为方法,如:

var o = {func: function(x){return x* x;}};var y = o.func(16);console.log(y);  // 256

赋值给数组元素,此时的函数可以不需要名字,即是匿名函数,如:

var arr = [function(x){return x*x},18];console.log(arr[0](arr[1]));  // 324 

函数作为参数传递,如:

function myFun(someFun,someArg){    return someFun(someArg);}function add(num){return num+10;}var result = myFun(add,10);alert(result); // 20function getGreeting(name){return "hello:"+name;}var result2 = myFun(getGreeting,"wangwei");  // wangweialert(result2);

说明:myFun接受两个参数,第一个参数是函数,第二个参数是要传递给该函数的一个值;

函数作为值的示例:

// 定义一些简单的函数function add(x,y){return x + y;}function subtract(x,y){return x - y;}function multiply(x,y){return x * y;}function divide(x,y){return x / y;}// operate函数将以上的函数作为参数,并传入两个操作数让其调用function operate(operator, num1, num2){    return operator(num1, num2);}// 调用var result = operate(add, operate(add, 2, 3), operate(multiply, 4, 5));console.log(result);  // (2+3) + 4 * 5 = 25// 改写// 使用函数直接量,定义在一个对象直接量中var operators = {    add: function(x,y){return x + y;},    subtract: function(x,y){return x - y;},    multiply: function(x,y){return x * y;},    divide: function(x,y){return x / y;},    pow: Math.pow  // 使用内置的Math对象的pow方法};// operate函数接受一个名字作为运算符,在operators对象中查找这个运算符// 然后将它作用于所提供的操作数function operate(operation, num1, num2){    if(typeof operators[operation] === "function")        return operators[operation](num1, num2);    else throw "unknown operator";}// 调用并计算var result = operate("add", "hello", operate("add", " ", "wangwei"));console.log(result);  // hello wangweiresult = operate("pow", 10,2);console.log(result); // 100

当函数作为值的一个典型的应用,就是在Array.sort()方法中使用,该方法用来对数组元素进行排序;因为排序的规则有很多,如:基于数值大小、字母表顺序、日期大小、从小到大等,所以sort()方法接受一个自定义函数作为参数,该自定义函数用来处理具体的排序操作,其原理是:对于任意两个值都返回一个值,以指定它们在在排序后的数组中的先后顺序;如:

function compare(x,y){    return x - y;}var arr = [1,88,3,5,12,18,67];console.log(arr.sort(compare));

Web前端开发之Javascript-零点程序员-王唯

c++ log函数_第18节 函数的形参和实参-Web前端开发之Javascript-王唯相关推荐

  1. date javascript 时区_第23节 Datejs 日期库-Web前端开发之Javascript-零点程序员-王唯

    Datejs 是一个开源的JavaScript库,用来解析.格式化和处理日期数据,支持多种语言的日期格式处理:官网:www.datejs.com/ Moment.js 是一个简单易用的轻量级JavaS ...

  2. BCSP-玄子前端开发之JavaScript+jQuery入门CH02_JavaScript函数

    BCSP-玄子前端开发之JavaScript+jQuery入门CH02_JavaScript函数 4.2 函数 4.2.1 什么是函数 类似于Java中的方法,是完成特定任务的代码语句块 特点 使用更 ...

  3. 如何快速学Web前端开发?JavaScript函数好学吗?

    如何快速学Web前端开发?JavaScript函数好学吗?很多企业在招聘Web前端工程师时会倾向于招聘JavaScript技术的人才,因此专业中必然要包含JavaScript知识.函数是为完成某一功能 ...

  4. 正则至少一个数字_好程序员web前端培训分享JavaScript学习笔记之正则

    好程序员web前端培训分享JavaScript学习笔记之正则,正则表达式,又名 "规则表达式" 由我们自己来书写 "规则",专门用来检测 字符串 是否符合 &q ...

  5. mysql独有的函数_数据库之MySQL函数(一)

    一.数学函数 1.绝对值函数 ABS(x) :返回 x 的绝对值 mysql> select ABS(2),ABS(-2.3),ABS(-22); 返回的结果如下: 数学学得好的大佬应该知道(本 ...

  6. 编写分段函数子函数_编写自己的函数

    编写分段函数子函数 PYTHON编程 (PYTHON PROGRAMMING) In Python, you can define your own functions. 在Python中,您可以定义 ...

  7. python里面的内置函数_【python】函数之内置函数

    今天来介绍一下Python解释器包含的一系列的内置函数,下面表格按字母顺序列出了内置函数: 下面就一一介绍一下内置函数的用法: 1.abs() 返回一个数值的绝对值,可以是整数或浮点数等. print ...

  8. 复平面上gamma函数_神奇的Gamma函数 (中)

    Gamma 函数欣赏 Each generation has found something of interest to say about the gamma function. Perhaps ...

  9. subtotal函数_星期五的Excel函数:将总计为SUBTOTAL的筛选列表

    subtotal函数 The Excel SUM function does a great job of adding numbers on a worksheet, and it's probab ...

  10. js 实现2的n次方计算函数_密码杂凑函数的基本性质探讨

    密码学研究的宗旨是保证数据和通信的机密性.完整性和认证性,其中完整性和认证性的实现依赖于一类关键的密码学函数---密码杂凑函数.密码杂凑函数通常用来计算数据的短"指纹"(也称杂凑值 ...

最新文章

  1. 【Kubernetes】两篇文章 搞懂 K8s 的 fannel 网络原理
  2. 如何快速融入团队(八)
  3. python中的datatype啥意思_案例中使用的是dataType,但是用在联系上面dataType不可用,必须改写成type:..._慕课问答...
  4. 二叉查找树 Java实现
  5. python和access哪个实用_access和python学哪个
  6. 【译】x86程序员手册37-第10章 初始化
  7. 367. 有效的完全平方数(二分法)
  8. mysql sum很慢,可以在MySQL中加快sum()吗?
  9. python oled_用官方的SSD1306.py 驱动 OLED
  10. linux-目录查询命令-目录内容查看-ls查询-tree查询-查询类容分类-不同颜色对应不同类型
  11. 【LeetCode】【HOT】543. 二叉树的直径(递归)
  12. 新能源车为什么不加变速箱解决高速高耗电的问题?
  13. Drive Scope for mac(硬盘检查分析工具)
  14. python刷题记录:买帽子
  15. 教大家做蛋黄酥的做法
  16. EMUI10安装java_速升级!荣耀Play推EMUI 9.1正式版更新:方舟编译器和EROFS系统来了 - IT之家...
  17. 对项目工时的估算----( PERT “计划评审技术” ) 三点估算法
  18. 数据透视:Excel数据透视和Python数据透视
  19. Graph Database 图数据库
  20. 微信小程序--图片转base64

热门文章

  1. 批处理计算n天前\后的日期
  2. 接口”安全机制”的设计
  3. mysql主从备份功能配置与測试
  4. cpu 之二 酷睿i3/i5/i7处理器到底简单区别
  5. java控制台输入输出
  6. vim安装vbundle
  7. pragma预处理指令详解
  8. SPI机制入门、SPI机制原理
  9. 群星服务器id不显示,群星代码([群星]求助,领袖特性代号怎么查看啊 NGA玩家社区)...
  10. CountDownLatch源码解读