深入了解 javascript 函数的参数

作者: b64c74899092 | 来源:发表于2017-09-04 11:42 被阅读314次

javascript 函数的参数和C++之类的强类型语言有很大的差别。下面详细介绍了 javascript 函数参数的主要特点。

显式参数和隐式参数

  • 显式参数(Parameters)
// 函数定义的时候列出函数的显式参数
function foo(parameter1, parameter2){} 
  • 隐式参数(Arguments):函数的隐式参数是函数调用时传递给函数真正的值。javascript 中的参数在内部是用一个数组来表示的,函数接收到的始终都是这个数组,而不关心数组中包含哪些参数,在函数体内可以通过 Arguments 对象来访问这个参数数组。

参数规则

  • 函数定义时显式参数没有指定数据类型。
  • 函数对隐式参数没有进行类型检测。
  • 函数对隐式参数的个数没有检测。(隐式参数个数和显式参数个数可以不同)

默认参数

如果函数在调用时没有提供隐式参数(也就是没有参数),参数会默认设置为: undefined

一般是没有什么问题,但是建议最后为参数设置一个默认值:

function a(x){
  if(x === undefined)
    x=0;
}

或者:

function a(x){
  x = x || 0;
}

Arguments 对象

如果函数调用的时候,传入的参数个数大于显式参数的个数,参数只能通过 Arguments 对象来调用。

Arguments 对象是 javascript 函数内置的对象,它包含了函数调用时传入的参数数组。通过 Arguments 对象可以很容易的对每个传入的参数进行操作:

function a(){
  var m = arguments[0]; // 第一个传入的参数 
  var n = arguments[1]; // 第二个传入的参数,如果只传入一个参数,那么该值为 undefined
  var l = arguments.length; // 该值对应的函数调用时传入参数的个数 
  var ll = a.length; // 该值对应的函数定义的参数个数
}

看起来 arguments 好像和数组一样,但是 arguments 是一个 object 对象,并不是数组,它是一个类数组对象,不能对它使用 push、join等方法。上面例子中的 arguments[i] 中的 i 只是作为 arguments 对象的属性,并不能理解为数组的下标。

内部属性

  • callee:arguments 对象有一个 callee 属性,该属性是一个指针,指向拥有这个 arguments 对象的函数。
    下面是经典的阶乘函数:
function factorial(num){
  if(num <= 1){
    return 1;
  }else{
    return num * factorial(num - 1);
  }
} 
console.log(factorial(5));//120

但是,上面这个函数的执行与函数名紧紧耦合在了一起,可以使用 arguments.callee 可以消除函数解耦:

function factorial(num){
  if(num <= 1){
    return 1;
  }else{
    return num * arguments.callee(num - 1);
  }
} 
console.log(factorial(5));//120

但在严格模式下,访问这个属性会抛出
TypeError 错误

function factorial(num){
  'use strict';
  if(num <= 1){
    return 1;
  }else{
    return num * arguments.callee(num - 1);
  }
} 
//TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
console.log(factorial(5));

这时,可以使用具名的函数表达式

var factorial = function fn(num){
  if(num <= 1){
    return 1;
  }else{
    return num * fn(num - 1);
  }
}; 
console.log(factorial(5));//120

同步

在形参个数和实参相同时,arguments 对象的值和对应形参的值保持同步:

function a(m){
  console.log(m,arguments[0]); // 1 1
  arguments[0] = 2;
  console.log(m,arguments[0]); // 2 2
  m = 3;
  console.log(m,arguments[0]); // 3 3
}
a(1);

注:虽然形参和对应 arguments 对象的值相同,但并不是相同的内存空间,它们是独立的内存空间,但是值会同步。

不过在严格模式下,它们的值是独立的:

function a(m){
  'use strict'; // 严格模式
  console.log(m,arguments[0]); // 1 1
  arguments[0] = 2;
  console.log(m,arguments[0]); // 1 2
  m = 3;
  console.log(m,arguments[0]); // 3 2
}
a(1);

当形参没有对应实参的时候,arguments 对象的值和形参并不同步:

function a(m){
  console.log(m,arguments[0]); // undefined undefined
  arguments[0] = 2;
  m = 3;
  console.log(m,arguments[0]); // 3 2
}
a();

参数传递

javascript 中所有函数的参数都是按值传递的。也就是说,把函数外部的值复制到函数内部的参数,就和把值从一个变量复制到另一个变量一样。

  • 基本类型:向参数传递基本类型的值时,被传递的值会被复制给一个局部变量。
  • 引用类型:在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部,当在函数内部重写引用类型的形参时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。

相关文章

  • 深入了解 javascript 函数的参数

    javascript 函数的参数和C++之类的强类型语言有很大的差别。下面详细介绍了 javascript 函数参...

  • 2019-06-26

    深入理解JavaScript 参数按值传递 定义:ECMAScript中所有函数的参数都是按值传递的。 值传递:函...

  • JavaScript函数、this以及闭包

    JavaScript笔记(三) 函数 理解函数 Javascript函数的参数与大多数其他语言中的函数的参数不同。...

  • javascript函数,以及闭包的理解

    javascript函数,以及闭包的理解 深入理解javascript函数定义与函数作用域深入理解javascri...

  • 从屌丝到架构师的飞越(JavaScript篇)-函数对象

    一、介绍 这节课呢,我们来了解的是JavaScript 函数定义,前面我们已经了解了函数的基本语法,下面我们来深入...

  • JavaScript学习笔记(三)

    主要源于廖雪峰老师的JavaScript教程 1. 高阶函数 参数传入函数 JavaScript的函数其实都指向某...

  • ES6 笔记 箭头函数

    箭头函数其实就是lambda函数,JavaScript中的匿名函数 多个参数时,参数外加上括号(或者使用rest ...

  • TypeScript函数使用

    使用函数 有可选参数的函数 与JavaScript不同,调用函数时传的参数的数量或者类型不符合函数中定义的参数要求...

  • 深入函数参数

    函数参数 Python允许具有可变长参数的函数。使用*args作为函数参数,可以将任意数量的参数传递给该参数。然后...

  • 2018-06-06

    JavaScript函数 1. arguments对象 — 函数的实参参数集合 // 循环...

网友评论

    本文标题:深入了解 javascript 函数的参数

    本文链接:https://www.haomeiwen.com/subject/zaisjxtx.html