学JS的心路历程-函式(二)arguments
参数(argument)与函式参数(parameter)
在讨论函式时,很多人都会把这两个搞混,我自己也不例外。
虽然讲错别人也听得懂,但是我们还是要搞清楚这两个的定义到底是什么!
参数是当我们呼叫函式时传递给它的值
参数是我们在函式定义中所列出的变量
看完还是有点不懂?没关系,上图!

声明式(declaration)与表达式(expression)
发现在前几天介绍声明函式时没有特别说明两者名称的差异,虽然这跟上面的参数与参数一样说错别人也懂(yjssqsdg),但我们还是要分清楚喔!
声明式:
function funA(){
…
}
表达式:
var myFun = function(){
…
}
隐含参数
在呼叫函式时候除了传递自己给的参数外,你知道还会传递两个隐含参数:arguments和this吗?
什么事「隐含」,就是这些参数没有明确列在函式署名(function signature)中,只会默默传递给函式,并且可以在函式内存取他们,也可以在函式中被引用。
我们今天只会先介绍arguments,this会在之后的篇幅中提到。
arguments
是传递给函式的所有参数之集合,不用管相对应的参数是否有明确定义。这也让我们可以实现JS本身不支持的函式重载(function overloading)及可变参数数量的可变函式(variadic function)。
讲到这边可能会有人困惑说什么是函式重载?所谓函式重载就是函式的名称都一样,但是会根据不同的输入拥有不同的输出。
看不太懂也没关系,在我们讲完arguments后会提到怎么实作。
我们先来看一个简单的例子:
function show(a,b,c){
console.log(a,b,c);
console.log(arguments);
console.log(arguments[0]);
console.log(arguments.length);
console.log(typeof arguments);
}
show(1,2,3);
可以看到arguments储存了所有传递参数的值。而且还可以用lenght属性,但这边要注意到,它并不是一个数组,是一个叫做类数组的东西,也就是说无法使用JS提供给array的函式库。
function show(a,b,c){
arguments.sort(function(a,b){
return a - b;
});
}
show(1,2,3);//Uncaught TypeError: arguments.sort is not a function
这边要注意到一点,如果我们修改了arguments的值,原本的参数也会被修改:
function modifyArg(a,b,c){
console.log(a,b,c);//1 2 3
arguments[0] *= 20;
console.log(a,b,c);//20 2 3
}
modifyArg(1,2,3);
在前面有提到过说可以利用arguments作可变函式:
function dynamicArg(){
console.log(arguments);
}
dynamicArg(1,2,3);//Arguments(3)[1,2,3,callee:ƒ,Symbol(Symbol.iterator):ƒ]
再来,我们来看一下到底怎么作函式重载呢:
function mutli(){
let argLength = arguments.length;
if(argLength ===1){
console.log(argLength[0])
}else if(argLength ===2){
console.log(argLength[0],argLength[1])
}
…
}
这是最简单的函式重载,虽然可以运作但实在看了头有点痛。
我们今天来假设一个情境,我们想要有一个函式可以对人名进行搜索,根据不同的参数长度回传搜寻的值,这时候我会就会需要一个object物件:
var people = {
name:[“Dean Edwards”,“Alex Russell”,“Dean Tom”,“Alex Tsai”,“Tom Cruise”,“Tom Ford”]
}
我们想要能find('Dean')时回传[“Dean Edwards”,“Dean Tom”];
find()时回传所有人;find('Tom Cruise')时回传[“Tom Cruise”]。
于是我们需要一个函式:
var people = {
name:[“Dean Edwards”,“Alex Russell”,“Dean Tom”,“Alex Tsai”,“Tom Cruise”,“Tom Ford”]
}
function addMethod(obj,key,fn){
var old = obj[key];
obj[key] = function(){
if(fn.length === arguments.length){
return fn(arguments);
} else if(typeof old ===“function”){
return old(arguments);
}
}
}
接着,我们就可以写搜索人名的函式了:
//没有参数传入,回传所有人
function findAll(){
return people.name;
}
//传入一个参数时,回传firstName相同的人名数组
function findFirstName(firstName){
var ret = [];
for(var i = 0;i < people.name.length;i++){
if(people.name[i].indexOf(firstName)!== -1){
ret.push(people.name[i]);
}
}
return ret;
}
//传入两个参数时,回传firstName和lastName都相同的人名数组
function findFullName(firstName,lastName){
var ret = [];
for(var i = 0;i < people.name.length;i++){
if(people.name[i] ===(firstName +“”+ lastName)){
ret.push(people.name[i]);
}
}
return ret;
}
写完之后,将他们经由addMethod()传入people物件里面:
addMethod(people,“find”,findAll);
addMethod(people,“find”,findFirstName);
addMethod(people,“find”,findFullName);
之后就可以用了:
console.log(people.find());//[“Dean Edwards”,“Alex Russell”,“Dean Tom”,“Alex Tsai”,“Tom Cruise”,“Tom Ford”]
console.log(people.find(“Tom”));//[“Tom Cruise”,“Tom Ford”]
console.log(people.find(“Dean Edwards”));//[“Dean Edwards”]
或许有人会很困惑,为什么我们可以这样用,让我们来逐一分析这个addMethod函式:
function addMethod(obj,key,fn){
var old = obj[key];
obj[key] = function(){
if(fn.length === arguments.length){
return fn(arguments);
} else if(typeof old ===“function”){
return old(arguments);
}
}
}
可以看到我们每次呼叫时,都会先储存原先的people.find到变量old,这时候就会造成闭包的现象(LeLeyuesao),这我们后面篇幅会提到,简单的说,我们可以藉由people.find不断往上找,直到找不到为止。
所以当我们呼叫people.find(“Tom”)时,会执行:
if(fn.length === arguments.length){
return fn(arguments);
}
else if(typeof old ===“function”){
return old(arguments);
}
这时候的fn是findFullName但由于传入参数长度跟findFullName长度不相等,所以会执行:
else if(typeof old ===“function”){
return old(arguments);
}
这时候的old等于people.find(“Tom”),但是里面包附的fn已经换成,
findFirstName由于传入参数长度跟findFirstName长度相等,便会直接执行,不会在往上找。
或许会有人认为,我为了写一个函式重载,还得写这么多复杂的函式,不如需要时在呼叫就好了啊!
但是函式重载的好处在于,只需要苦过一次,后面就可以用短短的一行函式就得到想要的结果了!
参考资料:
忍者JavaScript开发技巧探秘
JavaScript中的函数重载(Function overloading)
学JS的心路历程-函式(二)arguments的更多相关文章
- 学JS的心路历程 -函式(三)this
this是什么,取决于被呼叫的呼叫地点. 昨天有提到说,呼叫函式时候会传递隐含参数:arguments和this并讲解了arguments,今天我们就来探讨this吧! 什么是this 我们都会呼叫函 ...
- 学JS的心路历程-函式(六)其余参数及预设参数
今天我们要来介绍ES6新增的其余参数及预设参数! 其余参数rest parameter …numbers可以让我们表示不确定数量的参数,并将其视为一个数组: function getVal(…numb ...
- 学JS的心路历程-函式(五)箭头函式
箭头函式arrow function 为了能够以更简短的方式建立函式,ES6变推出了箭头函式. 用说明的可能会不太懂,我们先拿之前的数组排序例子来看: var arr = [2,1,6,12,3,77 ...
- 学JS的心路历程-函式(四)apply、call
从上一篇可以知道,不同的函式呼叫会造成this的不同,但我们能不能在呼叫时候明确指定呢? 当然可以.会有这个想法是因为往往在执行某支函式时想要用回呼函式(mizumisushi),但发现this总是显 ...
- 学习JS的心路历程-函式(一)
前几天有间单提到该如何声明函式及在Hositing中会发生什么事,但是函式的奥妙不仅于此. 身为一个使用JS的工程师,我们一定要熟悉函式到比恋人还熟! 这几天将会把函式逐一扒开跟各位一起探讨其中的奥妙 ...
- 学JS的心路历程-Promise(二)
昨天有说到Promise的创建以及then的用法,今天我们来看错误处理. then onRejected 我们昨天有提到说,then两个函式参数,onFulfilled和onRejected,而onR ...
- 学JS的心路历程-JS支持面向对象?(一)
昨天在看Prototype看到JS支持面向对象,被前辈问到说那什么是面向对象?JS是面向对象语言吗? 便开始了一连串艰辛爬文过程,今天就来看一下两者有什么差异吧(rgwyjc)! 首先面向对象有三大特 ...
- 学JS的心路历程 -物件与原型(二)
昨天有提到说Object.setPrototypeOf可以指定一个物件为另一个物件的原型,但有想过到底这个原型,也就是[[Prototype]]最终会到何处吗? 答案是Object.prototype ...
- 学JS的心路历程 - JS的Class
没错,你没有看错,虽然前面说JS是原型继承,但在ES6以后新增了class关键字!!! 不过底层实作仍然是以原型继承方式进行,所以基本上算是一个语法糖. 今天我们就来看一下如何使用吧! class 首 ...
随机推荐
- MySQL库操作,表操作,数据操作。
数据库服务器:本质就是一台计算机,该计算机上安装有数据库管理软件的服务端,供客户端访问使用. 1数据库管理系统RDBMS(本质就是一个C/S架构的套接字),关系型数据库管理系统. 库:(文件夹)- ...
- 自动化工具gulp搭建环境(详解)
src:读取文件和文件夹 dest:生成文件(写文件) watch:监控文件 task:定制任务 pipe:以流的方式处理文件 bower的安装和使 ...
- 零基础学习python_列表和元组(10-13课)
一时兴起今天又回过头来补一下列表和元组,先来说说列表哈,列表其实是python最经常用到的数据类型了,不仅经常用还很强大呢,这个跟C语言里面的数组是类似的,列表当然也可以增删改查,不过我可没打算用之前 ...
- oracle 表或视图不存在
导入导出时,会自动表名自动加上了““双引号需要将表名改一下就可以了 alter table "oldtablename" rename to newtableName;
- UINavigationController 返回到各级目录
[self.navigationController popViewControllerAnimated:YES]; UINavigationController返回总结: 1.弹出当前视图控制器(弹 ...
- J2SE 5.0-memory management whitepaper--delete
1.垃圾回收器期职责 开辟空间 任何引用可达的对象都在内存内 回收不再使用的内存 3.垃圾回收器概念 3.1.垃圾回收器期望的性能 垃圾回收器必须安全,存活的对象不应该被释放,应该释放的对象存活的时间 ...
- 【转载】Putty出现 Network error:Software caused connection abort
一.putty發生 network error 开始菜单进入regedit,尋找 HKEY_CURRENT_USER\Software\SimonTatham 并把这个目录下的子目录全部删除,删除前务 ...
- py库: pymysql、 json (mysql数据库)
数据库查询结果,用json返回: #连接数据库 import pymysql print(pymysql.VERSION) conn = pymysql.Connect(host='localhost ...
- [Writeup]与佛论禅
[Writeup]与佛论禅 垂死梦中惊坐起,李sin参悟佛真意 看题 沙雕sl宋雷发给我一道题 他用(Quoted-Printable)解出来一个奇怪经文(偷学) 李sin你怎么看?此中必有蹊跷! 前 ...
- DataBinding(二):DataBinding的基本用法
转自:DataBinding系列(二):DataBinding的基本用法 1.在xml中引入一些基础变量Variables data 标签中可以有任意数量的 variable 标签.这些变量可以使Ja ...