js 方法参数,js有参函数

  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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: