c++ log函数_第18节 函数的形参和实参-Web前端开发之Javascript-王唯
本内容是《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-王唯相关推荐
- date javascript 时区_第23节 Datejs 日期库-Web前端开发之Javascript-零点程序员-王唯
Datejs 是一个开源的JavaScript库,用来解析.格式化和处理日期数据,支持多种语言的日期格式处理:官网:www.datejs.com/ Moment.js 是一个简单易用的轻量级JavaS ...
- BCSP-玄子前端开发之JavaScript+jQuery入门CH02_JavaScript函数
BCSP-玄子前端开发之JavaScript+jQuery入门CH02_JavaScript函数 4.2 函数 4.2.1 什么是函数 类似于Java中的方法,是完成特定任务的代码语句块 特点 使用更 ...
- 如何快速学Web前端开发?JavaScript函数好学吗?
如何快速学Web前端开发?JavaScript函数好学吗?很多企业在招聘Web前端工程师时会倾向于招聘JavaScript技术的人才,因此专业中必然要包含JavaScript知识.函数是为完成某一功能 ...
- 正则至少一个数字_好程序员web前端培训分享JavaScript学习笔记之正则
好程序员web前端培训分享JavaScript学习笔记之正则,正则表达式,又名 "规则表达式" 由我们自己来书写 "规则",专门用来检测 字符串 是否符合 &q ...
- mysql独有的函数_数据库之MySQL函数(一)
一.数学函数 1.绝对值函数 ABS(x) :返回 x 的绝对值 mysql> select ABS(2),ABS(-2.3),ABS(-22); 返回的结果如下: 数学学得好的大佬应该知道(本 ...
- 编写分段函数子函数_编写自己的函数
编写分段函数子函数 PYTHON编程 (PYTHON PROGRAMMING) In Python, you can define your own functions. 在Python中,您可以定义 ...
- python里面的内置函数_【python】函数之内置函数
今天来介绍一下Python解释器包含的一系列的内置函数,下面表格按字母顺序列出了内置函数: 下面就一一介绍一下内置函数的用法: 1.abs() 返回一个数值的绝对值,可以是整数或浮点数等. print ...
- 复平面上gamma函数_神奇的Gamma函数 (中)
Gamma 函数欣赏 Each generation has found something of interest to say about the gamma function. Perhaps ...
- subtotal函数_星期五的Excel函数:将总计为SUBTOTAL的筛选列表
subtotal函数 The Excel SUM function does a great job of adding numbers on a worksheet, and it's probab ...
- js 实现2的n次方计算函数_密码杂凑函数的基本性质探讨
密码学研究的宗旨是保证数据和通信的机密性.完整性和认证性,其中完整性和认证性的实现依赖于一类关键的密码学函数---密码杂凑函数.密码杂凑函数通常用来计算数据的短"指纹"(也称杂凑值 ...
最新文章
- 【Kubernetes】两篇文章 搞懂 K8s 的 fannel 网络原理
- 如何快速融入团队(八)
- python中的datatype啥意思_案例中使用的是dataType,但是用在联系上面dataType不可用,必须改写成type:..._慕课问答...
- 二叉查找树 Java实现
- python和access哪个实用_access和python学哪个
- 【译】x86程序员手册37-第10章 初始化
- 367. 有效的完全平方数(二分法)
- mysql sum很慢,可以在MySQL中加快sum()吗?
- python oled_用官方的SSD1306.py 驱动 OLED
- linux-目录查询命令-目录内容查看-ls查询-tree查询-查询类容分类-不同颜色对应不同类型
- 【LeetCode】【HOT】543. 二叉树的直径(递归)
- 新能源车为什么不加变速箱解决高速高耗电的问题?
- Drive Scope for mac(硬盘检查分析工具)
- python刷题记录:买帽子
- 教大家做蛋黄酥的做法
- EMUI10安装java_速升级!荣耀Play推EMUI 9.1正式版更新:方舟编译器和EROFS系统来了 - IT之家...
- 对项目工时的估算----( PERT “计划评审技术” ) 三点估算法
- 数据透视:Excel数据透视和Python数据透视
- Graph Database 图数据库
- 微信小程序--图片转base64