js 方法参数,js有参函数
参数是内部函数和外部函数之间的桥梁。下面这篇文章就带你了解一下JavaScript函数中的参数,希望对你有所帮助!
一、函数的形参和实参
函数的参数会出现在两个地方,即定义函数的地方和调用函数的地方。这两个地方的参数不一样。
形参(形式参数)
出现在函数定义中的参数可以看作是一个占位符。它没有数据,只能等到函数被调用才能接收传入的数据,所以叫形参,简称形参。
实参(实际参数)
调用函数时给出的参数包含实数据,函数内部的代码会用到这些实数据,所以称之为实参数,简称实参。
形参和实参的区别和联系
1)参数变量只在函数被调用时分配内存,调用后立即释放内存,所以参数变量只在函数内部有效,不能在函数外部使用。
2)自变量可以是常量、变量、表达式、函数等。无论是什么类型的数据,在进行函数调用时都必须有一定的值,这样这些值才能传递给形参。所以要用赋值,输入等。预先获取参数的特定值。
3)实参和形参在数量、类型、顺序上必须严格一致,否则会出现“类型不匹配”的错误。当然,如果可以进行自动类型转换或强制类型转换,实参类型也可以不同于形参类型。
4)函数调用中的数据传递是单向的,只能将参数的值传递给参数,而不能将参数的值传递回参数;换句话说,一旦数据传输完成,实参和形参就不再相关。因此,在函数调用过程中,形参值的变化不会影响实参。
5)虽然形参和实参可以同名,但两者相互独立,互不影响,因为实参在函数外部有效,而形参在函数内部有效。
二、参数传递
函数允许我们传入数据,这些数据会影响函数的执行结果,使函数更加灵活和可重用。
函数foo(a,b) {
console.log([a,b]);
}
foo(1,2);//Output [1,2]本例中,A和B属于函数中的局部变量,只能在函数中访问。调用该函数时,传递的数据将匹配相应的位置,并分别赋给A和B。
创建函数时,函数名后括号中设置的参数称为形参;当一个函数被调用时,函数名后圆括号中传入的参数被调用实参。在上面的例子中,A和B是形式参数,传入的1和2是实际参数。
因为该参数是一个声明变量,所以不能再用let和const重复声明。
函数foo(a,b) {
设a=1;//报告了错误,声明了
常数b=1;//报告错误,已经声明了B
}JavaScript中的所有函数传递都是按值传递,而不是按引用传递。所谓值是指直接存储在变量中的值。如果一个对象作为参数传递,那么这个值就是对这个对象的引用,而不是对象本身。其实这是一个隐式赋值的过程,所以在给函数传递参数的时候相当于从一个变量赋值到另一个变量。
原始值:
功能添加(数量){
返回编号1;
}
设count=5;
设结果=相加(计数);//这里参数传递的过程可以看成num=count
console.log(计数);//5
console.log(结果);//6参考值:
函数集名(对象){
Obj.name=小明;
}
let person={ };
setName(人);//这里参数传递的过程可以看成obj=person
console.log(人);//{name:晓明 }
三、理解参数
JavaScript中的函数既不会检测参数的类型,也不会检测传入参数的个数。定义函数时设置两个参数并不意味着调用时必须传入两个参数。不管实际调用中传递的是一个还是三个参数,即使没有传递参数也不会报错。
所有函数(不是箭头)都有一个特殊的类数组对象命名参数(不是数组的实例),它保存所有参数的副本。我们可以通过它根据数组的索引访问得到所有参数的值,或者访问它的arguments.length属性来确定实际调用函数时传入的参数个数。
例如:
函数foo(a,b) {
console . log(arguments[0]);
console . log(arguments[1]);
控制台. log(arguments . length);
}
foo(10,20);//依次输出10,20,2。在上面的例子中,foo()函数的第一个参数是A,第二个参数是b,通过arguments[x]可以得到相同的值。因此,您甚至可以在不设置形参的情况下声明函数。
函数foo() {
console . log(arguments[0]);
console . log(arguments[1]);
}
foo(10,20);//依次输出10和20。可见JavaScript函数的形参只是为了方便而写的。无论你想传递多少参数,都不会有错误。
另一个需要注意的是,arguments可以和参数一起使用,arguments对象中的值将与相应的参数同步。例如:
函数foo(a) {
参数[0];
console . log(a);
}
foo(10);//输出11
//-
函数foo2(a) {
a;
console . log(arguments[0]);
}
foo 2(10);//Output 11当参数[0]或a的值被修改时,另一个也随之改变。这并不意味着它们访问相同的内存地址。毕竟我们传入了一个原始值。它们在内存中仍然是分开的,但是它们的值通过内部机制保持同步。
此外,如果缺少参数,此参数的值将不会与arguments对象中的相应值同步。例如,在下面的示例中,只传递了一个参数,因此arguments中只有一个参数值。此时,将arguments[1]设置为函数中的某个值将不会与第二个参数同步,例如:
函数foo(a,b) {
arguments[1]=2;
console . log(b);
}
foo(1);//输出未定义。在这个例子中,参数B没有传入任何参数,默认情况下它的值是未定义的。但是如果:
foo(1,未定义);//当output 2作为undefined手动传入时,arguments数组中会出现一个值为undefined的元素,这个元素仍然可以与b的值同步。
严格模式,arguments对象中的值和参数将不再同步。当然,如果传入一个参考值,它们仍然会相互影响,但这只是参考值的特性。所以在开发中最好不要依赖这种同步机制,也就是说不要在arguments对象中同时使用参数及其对应的值。
箭头函数中没有 arguments
如果函数是使用arrow语法定义的,则函数中没有arguments对象,只能通过定义的参数来访问它。
让foo=()={
console . log(arguments[0]);
} foo();//报告错误,参数未定义。在某些情况下,可以访问参数:
函数fn1(){
设fn2=()={
console . log(arguments[0]);
}
fn2();
} fn1(5);但这个论证不是箭头函数的,而是外部普通函数的。当在arrow函数中访问参数时,可以沿着作用域链找到外部函数的参数。
四、将对象属性用作实参
当一个函数包含多个形参时,调用该函数就变得很麻烦,因为你总是要保证传递的形参放在正确的位置。有没有办法解决参数传递顺序的限制?
因为对象属性是无序的,所以相应的值由属性名称决定。因此,您可以通过传入对象将对象中的属性作为实参数,这样参数的顺序就无关紧要了。
函数foo(obj) {
console.log(obj.name,obj.sex,obj . age);
}
Foo({性别:男,年龄:18,姓名:小明 });//肖明南18
五、参数默认值
如果调用函数时缺少提供的实参,则参数的默认值是未定义的。
有时我们希望设置特定的默认值。当ES6之前不支持显式默认值时,我们只能采用一种变通方法:
函数sayHi(名称){
name=name everyone
console.log( Hello name !);
}
say hi();//输出“大家好!”上面的方法很简单,但是缺点是如果传递的实参的布尔值为假,实参就不起作用。如果需要更精确,可以用If语句或者三元表达式来判断参数是否等于未定义。如果是,则缺少此参数:
//if语句判断
函数sayHi(名称){
if (name===undefined) {
name= everyone
}
console.log( Hello name !);
}
//三元表达式判断
函数sayHi(名称){
name=(name!==未定义)?姓名:所有人;
console.log( Hello name !);
}ES6要方便得多,因为它支持设置默认值的显式方式,就像这样:
function say hi(name= every one ){//定义函数时,直接给参数赋值。
console.log( Hello name !);
}
say hi();//输出“大家好!”
say hi(‘托尼’);//输出“你好,托尼!”
sayHi(未定义);//输出“大家好!”这些结果表明,它还通过参数是否等于未定义来确定参数是否缺失。
默认值不仅可以是值,还可以是任何合法的表达式,甚至是函数调用:
函数sayHi(name=every one) {
console.log( Hello name !);
}
say hi();//输出“大家好!”
//-
函数foo() {
console . log( call foo );
返回“托尼”;
}
函数sayHi(name=foo()) {
console.log( Hello name !);
}
say hi();//输出调用foo
//输出“你好,托尼!”
sayHi(未定义);//输出调用foo
//输出“你好,托尼!”
赛希(‘约翰’);//输出“你好,约翰!”如你所见,函数参数的默认值只有在函数被调用时才会被计算,而在函数未定义时不会。
参数默认值的位置
通常我们会为参数设置默认值,这样在调用函数时可以适当省略参数的输入。这里需要注意的是,如果有多个参数,带默认值的参数如果不放在最后,实际上是不能省略的。
函数fn(x=1,y) {
console.log([x,y]);
}
fn();//Output [1,未定义]
fn(2);//Output [2,未定义]
fn(,2);//报告错误,语法错误(此处不支持数组之类的空槽)
fn(未定义,2);//output [1,2](那还不如传一个1方便!)在上面的例子中,为参数x设置的默认值是没有意义的。因此,最好将带有默认值的参数放在最后:
函数fn(x,y=2) {
console.log([x,y]);
}
fn();//Output [undefined,2]
fn(1);//输出[1,2]
Fn(1,1) //Output [1,1]参数的省略问题
当给多个参数设置默认值时,问题又来了。不能省略前面的参数,只能传入最后一个的实际参数。
函数fn(x,y=2,z=3) {
console.log([x,y,z]);
}
Fn(1,10)///错误报告我们之前知道,通过传入对象可以避免参数顺序的限制。如何实现参数的默认值?用,if语句或者三元表达式来判断也是一种解决方法,但是好像有点落后。接下来,我们将讨论ES6中的两种新方法。
参数默认值和 Object.assign() 结合使用
函数fn(obj={}) {
let defaultObj={
x:未定义,
y: 2,
z: 3
}
let result=object . assign(default obj,obj);
console.log([result.x,result.y,result . z]);
}
fn();//Output [undefined,2,3]
fn({ x: 1,z:10 });//Output [1,2,10]在上面的例子中,函数中定义了一个对象defaultObj,它的属性被灵活地用作参数的默认值。然后,通过使用Object.assagin()将传入的对象与默认对象合并。defaultObj中的属性将被Obj的相同属性覆盖,obj中的其他属性将被赋给defaultObj。这里,使用一个变量来接收返回的合并对象。
同时,形参obj的默认值也被设置为空对象,这样可以防止函数在不传递任何参数的情况下调用,因为这样会导致Object.assign()接收的第二个参数未定义,从而导致错误。
参数默认值和解构赋值结合使用
当一个函数被调用时,实参和形参的匹配实际上是一个隐式赋值过程。因此,参数传递也可以被解构和赋值:
函数fn({ x,y=2,z=3 }) {
console.log([x,y,z]);
}
fn({ });//Output [undefined,2,3]
fn({ x: 1,z:10 });//Output [1,2,10]本例中只使用了对象的解构赋值的默认值,函数参数的默认值还没有使用。如果调用函数时没有传递参数,也会产生错误,因为这导致参数初始化时解构赋值失败,相当于执行代码{x,y=2,z=3}=undefined。
同样,可以使用参数默认值的语法为{x,y=2,z=3}设置一个默认的解构对象,这样函数就可以在不传递参数的情况下顺利执行:
函数fn({ x,y=2,z=3 }={}) {
console.log([x,y,z]);
}
fn();//Output [undefined,2,3]这里有双默认值,可能有点绕,所以用一个伪代码来解释上面的参数初始化过程就是:
If(参数==={.}){//当fn({.});
{ x,y=2,z=3 }={.};
} else if(argument===undefined){//当fn();
{ x,y=2,z=3 }={ }
}双默认值有一个细节需要特别注意,就是解构赋值值默认值和函数参数默认值的区别。请参见以下示例:
函数fn ({ x=1 }={},{ y }={ y: 2 }){
console.log(x,y);
}
fn();//输出1 2
fn({ x: 10 },{ y:20 });//输出10 20
fn({},{ });//1未定义在这个函数中,有两组参数被解构赋值。似乎X和Y都设置了默认值。虽然是两种不同的形式,但显然在所有情况下结果都不一样。当传入的参数是{}时,Y不会得到默认值2。为什么会这样呢?结合前面的伪代码示例:
fn({ x: 10 },{ y:20 });//初始化时:{x=1}={x: 10 },{y}={y: 20}
fn({},{ });//初始化时:{x=1}={},{y}={}当传入的参数为{}时,函数参数没有缺失或未定义,所以函数参数的默认值不起作用。同时,{}中没有X和Y的对应值。X得到的值1是解构赋值的默认值,而Y的值因为没有设置,所以默认是未定义的。
参数默认值的作用域与暂时性死区
还有一个小细节。一旦参数设置了默认值,它们就会形成自己的范围(包装在(.)),所以它们不能引用函数体中的变量:
函数foo(a=b) {
设b=1;
}
foo();//报告一个错误。b是未定义的,但是这个范围只是暂时的。参数初始化后,这个范围就不存在了。
它也符合通用范围的规则:
设b=2;
函数foo(a=b) {
设b=1;
返回a;
}
foo();//2在上面的例子中,有一个全局变量B,所以参数A会得到全局变量B的值。
当然,如果在参数的作用域中有一个参数B,它将首先得到:
设b=2;
函数foo(b=3,a=b) {
返回a;
}
foo();//3为多个参数设置默认值,将按照“临时死区”的规则依次初始化,即前面的参数不能引用后面的参数:
函数foo(a=b,b=2) {
返回a b;
}
foo();//报错,初始化前无法访问B
六、参数的收集与展开
剩余参数
ES6提供了语法(.变量名)* * rest parameters (rest)**,可以收集函数的冗余实参(即没有对应参数的实参),这样就不再需要使用arguments object来获取。使用该参数.操作符会变成一个数组,多余的参数会放入这个数组。
其余参数的基本用法:
函数和(a,值){
for(字母值){
a=val
}
返回a;
}
sum(0,1,2,3);//6在上面的例子中,参数初始化时,先按照位置进行匹配,将0赋给A,然后将剩下的参数1,2,3放入数组值中。
下面是使用arguments对象和剩余参数分别获取参数的对比示例:
//参数的编写
函数sortNumbers() {
返回Array.prototype.slice.call(参数)。sort();
}
//其余参数的写入
const sortNumbers=(.数字)={
返回numbers . sort();
}可以看出其余参数的写法更加简洁。arguments虽然是类数组,是迭代对象,但毕竟不是数组。它不支持数组方法。我们在使用实参的时候,如果要调用数组方法,必须先用Array.prototype.slice.call将其转换成数组。
剩下的参数不同于arguments对象,它是一个真正的数组实例,可以很容易地使用Array方法。箭头函数也支持其余的参数。
此外,使用剩余的参数不会影响arguments对象的功能,但它仍然可以在调用函数时反映传入的参数。
剩余参数的位置
剩下的参数必须是最后一个参数,否则将会报告错误。
//报告错误
功能fn1(a,休息,b) {
console.log([a,b,rest]);
}
//正确书写
功能fn2(a,b,休息){
console.log([a,b,rest]);
}
FN (1,2,3,4)//Output [1,2,[3,4]]展开语法
之前,我们知道如何将冗余参数收集到一个数组中,但有时我们需要做一些相反的事情,比如将数组中的元素传递到一个函数中,而不是传递到一个数组中,就像这样:
函数和(.值){
设sum=0;
for(字母值){
sum=val
}
返回总和;
}
设arr=[1,2,3,4];
总和(arr);//01,2,3,4 上面例子中的函数将所有传入的值相加。如果你直接传入一个数组,你不会得到想要的结果。
在示例中,当传入一个数组时,values的值将变成[[1,2,3,4]],导致数组值中只有一个元素,并且这个元素的类型是array。那么函数的返回值就是数值0和数组[1,2,3,4]相加的结果。两者都是隐式转换成字符串,然后加在一起,这是一种字符串拼接效果。
要反汇编数组传入函数,不可能一个一个传入参数——sum (arr [0],arr [1],arr [2],arr [3])。因为你并不总是知道数组中有多少元素,而且数组中可能有很多元素,所以手动传递是不明智的。
使用apply()方法是可行的:
sum.apply(null,arr);//10但是这不是最优解,所以重点来了!
ES6的新* * spread)**语法* *可以帮助我们面对这种情况。这也是使用.变量名。虽然它与其余参数的语法相同,但其目的完全相反。它可以将迭代对象分割成逗号分隔的参数序列。
当调用该函数时,其应用程序如下所示:
总和(.arr);//10
//相当于sum(1,2,3,4);它甚至可以随意使用常规值,没有前后位置限制,还可以同时传入多个迭代对象:
总和(-1,arr);//9
总和(.arr,5);//15
总和(-1,arr,5);//14
总和(-1,啊,[5, 6, 7]);//27扩展运算符.相当于手动为我们传递参数。函数只知道收到的参数是单个值,不会因为扩展运算符的存在而有其他影响。
总结
参数是函数中声明的局部变量。实际传递给函数的参数被赋值给参数,函数的参数传递实际上是一个隐式赋值过程。
形式参数和实际参数的数量可以不相等:
缺少参数的表单参与将获得未定义的默认值。
附加参数,可通过arguments对象访问,但arrow函数除外。
您可以传入对象,使参数的顺序变得不重要,并让对象中的属性成为真正的参数。
ES6的参数默认值为——。调用该函数时,参数的默认值缺失或未定义。
有默认值的参数只有放在最后一个位置才能省略。
参数设置的默认值不能引用函数体中的变量,但可以引用前面的参数和外部变量。
通过Object.assign()或解构赋值实现默认值,可以使参数传递的方式更加灵活。
其余参数和自变量之间的主要区别:
其余参数只包含没有对应形参的实参,而arguments对象包含传递给函数的所有实参。
剩下的参数是真正的数组实例,而实参只是类数组对象。
其余的参数和扩展语法都采用.接线员。在该功能的相关场景中:
出现在函数参数表的末尾,是剩余的参数。
出现在函数调用中时,是扩展语法。
【相关推荐:javascript学习教程】以上是一篇详细讲解JavaScript函数中参数的文章的详细内容。请多关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。