基础教程 5. arguments、递归和函数表达式

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战javascript

1、函数的实参集合-arguments

  • 如今有个需求,须要写一个方法,求10数的和。

代码以下:html

function sum(a, b, c, d, e, f, g, h, i, j) {
  var total = a + b + c + d + e + f + g + h + i + j;
  return total;
}

sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
复制代码

函数形参的局限性:java

  1. 由于形参和实参是一一对应的,若是想要多少传递多少实参,就要设置多少形参,这很不方便,如今是10个,若是是100个,就要设置100个形参。
  2. 若是实参个数不固定,可能10个可能2个,还可能100个,因此此时形参没法设置。
  • 需求2:须要写一个方法,实现能够求任意多个数字之和;

任意多个实参,此时形参不固定了。咋办?数组

为了解决上面的形参的种种限制,浏览器为函数内置一个arguments对象;浏览器

arguments:arguments叫作内置的实参集合,这个对象里面包含了函数执行时传递进来的全部实参(内置:函数天生自带的机制,不论是否设置了形参,也无论你是否传递了实参,arguments一直都存在)。markdown

使用arguments:函数

function sum2(n, m) {
  console.log(n, m);
  console.log(arguments);

   arguments它是一个类数组(不是数组,不能直接使用数组中的方法)
   即便设置形参变量,形参该是什么仍是什么,可是arguments存储的是全部传进来的实参,因此arguments被称为 实参集合
   咱们发现它有索引,有length,能够用for循环遍历
   {
     0: 1,
     1: 2,
     2: 5,
     3: 7,
     4: 8
     length: 5,
     callee: 存储的当前函数自己 arguments.callee == sum2 -> true
    }



}

sum2(1, 2, 5, 7, 8);
复制代码

ES6 不定参数

  • ES6中提供了一个功能和arguments的功能类似的功能——不定参数
function sum(...arg) {
   ...叫作展开运算符
   arg 是一个形参变量
  console.log(arg);  arg是一个数组
}
sum(1, 2, 4, 5, 7);
复制代码
  • arguments 和 不定参数的不一样
  1. arguments是函数天生自带的属性不须要声明,而不定参数须要声明
  2. arguments是类数组,而不定参数是数组

任意数求和:

思路:post

  1. 既然是任意数,那么确定使用函数的arguments
  2. arguments里面存储着全部的实参,咱们须要把这些实参一个一个的取出来(遍历),而后加给一个基础值上
  3. 把结果return出去

基础版:ui

function sum3() {
   1. 设立初始值
  var total = 0;

   2. 遍历arguments
  for (var i = 0; i < arguments.length;i++) {
    var item = arguments[i];
    total += item;
  }
   3. 把计算结果返回
  return total;
}

var result = sum3(1, 2, 4, 5);
console.log(result);
复制代码

升级版:为了提升代码的健壮性,咱们累加的时候须要判断一下咱们传进来的实参是否是一个数字,若是不是数字,咱们先给它转成数字,而后再看转换后是否是有效数字,若是是再加,若是不是就不加了。spa

function sum4() {
   1. 设立初始值
  var total = 0;
   2. 遍历arguments对象,取出每一项
  for (var i = 0; i < arguments.length; i++) {
     3. 无论你传进来的是否是数字,都转一次
    var item = Number(arguments[i]);
     4. 判断转换后的结果是否是有效数字累加,非有效数字直接跳过
    if (!isNaN(item)) {
       若是不是NaN就让total加等于item
      total += item;
    }
  }
  return total;
}
console.log(sum4(10, '20', 'aa'));  30

复制代码

2、函数表达式

  • 函数分类:
  1. 实名函数:有函数名的
  2. 匿名函数:没有函数名的

2.1 函数表达式:把函数当作赋值给变量或者元素对象的事件属性 2.2 自执行函数:建立和执行一块儿完成的

  • 函数表达式:
  1. 把函数当成一个值赋值给变量或者对象的属性
var fn = function () {
  console.log('我是一个函数表达式');
};
fn();  fn是一个变量名,它表明的也是一个函数

 赋值给元素对象的事件属性:
oBox.onclick = function () {};

 普通对象的属性值:

var obj = {
  getName: function () {
    console.log('江外琉璃')
  }
}
obj.getName();  由于obj.getName 是一个函数,所以也能够执行
复制代码
  1. 自执行函数:函数的定义和声明都放在一块儿了
(function (i) {
   第一部分是函数定义
  console.log('i 是', i);
})(10); 后面的小括号放在函数后面就是让函数执行的

 如下都是自执行函数
~function (i) {
  console.log(i);
}(10);

+function (i) {
  console.log(i);
}(10);

!function (i) {
  console.log(i);
}(10);
复制代码

3、函数递归

函数:分为定义部分和执行部分

函数递归(recursion):在函数体内部,调用函数自身,达到重复某一行为的目的。

  • 需求:写一个方法求出 1-10之间全部数的数字之和
function rSum(num) {
  if (num === 10) {
    return 10
  }
  return num + rSum(num + 1)
   若是函数的返回值遇到一个表达式,那么函数会等着这个表达式求值完成最后把这个值返回出去。
   return 1 + rSum(2)
   return 1 + 2 + rSum(3)
   return 1 + 2 + 3 + rSum(4)
   return 1 + 2 + 3 + 4 + rSum(5)
   return 1 + 2 + 3 + 4 + 5 + rSum(6)
   return 1 + 2 + 3 + 4 + 5 + 6 + rSum(7)
   return 1 + 2 + 3 + 4 + 5 + 6 + 7 + rSum(8)
   return 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + rSum(9)
   return 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + rSum(10)
   return 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10
}
console.log(rSum(1));
复制代码
  • 需求:求1-10中的是3的倍数的全部数之和。
function rSum2(num) {
  if (num === 10) {
    return 0
  }
  if (num % 3 === 0) {
    return num + rSum2(num + 1)
  } else {
    return rSum2(num + 1);
  }
   return rSum2(2)
   return rSum2(3)
   return 3 + rSum2(4)
   return 3 + rSum2(5)
   return 3 + rSum2(6)
   return 3 + 6 + rSum2(7)
   return 3 + 6 + rSum2(8)
   return 3 + 6 + rSum2(9)
   return 3 + 6 + 9 + rSum(10)
   return 3 + 6 + 9 + 0
}
console.log(rSum2(1));
复制代码

注意:递归和for循环同样,在使用时考虑好递归终止的条件。否则就会形成死循环,致使栈内存溢出(stack overflow)

4、数组经常使用方法

I 数组的删除和追加

  1. => push
  • 做用:向数组末尾追加项(能够多项,多项直接用逗号分隔)
  • 参数:须要添加到数组的项
  • 返回值:数组追加项以后的长度
  • 原数组是否改变:是
var ary1 = [1, 2, 3];
var r1 = ary1.push(4, 5);
console.log(ary1, r1);
复制代码
  1. => pop
  • 做用:删除数组末尾一项
  • 参数:无
  • 返回值:被删除的数组项
  • 原数组是否改变:是
var ary2 = [1, 2, 4];
var r2 = ary2.pop();
console.log(ary2, r2);
复制代码
  1. => unshift
  • 做用:向数组开头添加项
  • 参数:须要追加到开头的项
  • 返回值:追加完内容后的数组新长度
  • 原数组是否改变:是
var ary3 = [1, 2, 3];
var r3 = ary3.unshift(4, 5);
console.log(ary3, r3);
复制代码
  1. => shift
  • 做用:删除数组起始一项
  • 参数:无
  • 返回值:被删除的项
  • 原数组是否改变:是
var ary4 = [1, 2, 3];
var r4 = ary4.shift();
console.log(ary4, r4);
复制代码
  1. => splice(n, m)
  • 做用:从索引为n开始删除m个
  • 参数:起始索引n,要删除的个数
  • 返回值:由删除的项组成新数组
  • 原数组是否改变:是
var ary5 = [1, 2, 3];
var r5 = ary.splice(1, 2);
console.log(ary5, r5);
复制代码
  1. => splice(n, m, x)
  • 做用:从索引n开始删除m个,用x替换删除的部分
  • 参数:起始索引,删除个数,用来替换的数组项x
  • 返回值:被删除的项组成的新数组
  • 原数组是否改变:是
var ary6 = [1, 2, 3];
var r6 = ary6.splice(1, 1, 5);
console.log(ary6, r6);

复制代码
  1. => splice(n, 0, x)
  • 做用:从索引n开始删除0个,把x插入到n的前面
  • 参数:起始索引,删除个数0,x
  • 返回值:空数组
  • 原数组是否改变:是
var r7 = ary.splice(1, 0, 5);
var ary7 = [1, 2, 3];
console.log(ary7, r7);

复制代码

II. 数组复制、拼接

  1. slice(n, m)
  • 做用:从索引n开始复制到索引m(不包括m)
  • 参数:起始索引n,终点索引m; 注意:m不写就是复制到最后一项,若是n和m都不写也是从开头复制到末尾
  • 返回值:复制的项组成的新数组
  • 原数组是否改变:否
var ary8 = [1, 2, 4, 5];
var r8 = ary8.slice(1, 3);
var r9 = ary8.slice(1);
var r10 = ary8.slice();
var r11 = ary.slice(0);
console.log(r8);
console.log(r9);
console.log(r10);
console.log(r11);

复制代码
  1. => concat()
  • 做用:将数组拼接起来
  • 参数:须要拼接的数组或者数组项
  • 返回值:拼接事后的新数组
  • 原数组是否改变:否
var ary12 = [1, 3, 5, 7];
var r12 = ary12.concat([9, 11]);  参数传递一个数组
console.log(ary12, r12);

var r13 = ary12.concat(9, 11);  参数传递数组项
console.log(ary12, r13);

var r14 = ary12.concat();  一个参数不传至关于把数组复制一份
console.log(r14);
console.log(r14 === ary12);  false

复制代码

III. 数组的转换成字符串

  1. => join()
  • 做用:根据参数指定的分隔符把数组连接成字符串
  • 参数:分隔符,不指定时默认空字符串
  • 返回值:拼接事后的字符串
  • 原数组是否改变:否
var ary15 = [1, 3, 5, 7];
var str15 = ary15.join('+');
console.log(ary15, str15);

复制代码
  1. => toString()
  • 做用:把数组转换成字符串
  • 参数:无
  • 返回值:字符串
  • 原数组是否改变:否
var ary16 = [1, 2, 5, 8];
var str16 = ary16.toString();
console.log(ary16, str16);

复制代码

IV 数组项是否在数组中出现过

  1. => indexOf(x)
  • 做用:数组项x在数组中第一次出现的索引位置
  • 参数:数组项x
  • 返回值:若是数组中存在该项,就返回该项第一次出现的索引,若是不存在,则返回 -1
  • 原数组是否改变:否
var ary17 = [1, 3, 5, 7];
var r17 = ary17.indexOf(3);
console.log(ary17, r17);

var r18= ary17.indexOf('bingo');
console.log(ary17, r18);  -1
复制代码
  1. => lastIndexOf(x)
  • 做用:数组项x在数组中最后一次出现的索引位置
  • 参数:数组项x
  • 返回值:若是数组中存在该项,就返回该项最后一次出现的索引,若是不存在,则返回 -1
  • 原数组是否改变:否
var ary19 = [1, 3, 5, 7, 3];
var r19 = ary19.lastIndexOf(3);
console.log(ary19, r19);

var r20 = ary19.lastIndexOf('bingo');
console.log(ary19, r20);  -1

复制代码

V. 数组排序和倒序

  1. => sort(function (a, b) { return a - b

})

  • 做用:给数组按照升序或者降序排列
  • 参数:回调函数
  • 返回值:若是回调函数return a - b 就返回升序排列后的数组
  • 若是回调函数return b - a,返回降序排列后的数组;
  • 原数组是否改变:是
var ary21 = [1, 5, 2, 6, 4];
var r21 = ary21.sort(function (a, b) {
  return a - b
});
var r22 = ary21.sort(function (a, b) {
  return b - a;
});
console.log(ary21, r21, r22);

复制代码
  1. reverse()
  • 做用:让数组翻转过来排列
  • 参数:无
  • 返回值:翻转事后的数组
  • 原数组是否改变:是
var re = ary21.reverse();
console.log(ary21, re);

复制代码

VI 数组的遍历方法(遍历:就是把数组里面的每一项都取出来)

    1. forEach(function (item, index) {
    在回调函数里能够操做这些值

})

  • 做用:遍历数组
  • 参数:回调函数(回调函数的参数:item是遍历时每个数组项,index是这个数组项的索引)
  • 返回值:无
  • 原数组是否改变:否
var ary23 = [1, 2, 5, 7, 9];

var r23 = ary23.forEach(function (item, index) {
  console.log(item, index);
});
console.log(ary23, r23);

复制代码
  1. => map(function (item, index) {})
  • 做用:将原数组映射成一个新数组
  • 参数:回调函数(回调函数的参数同forEach)
  • 返回值:由回调函数的返回值组成的新数组
  • 原数组是否改变:否
var ary24 = [1, 2, 5];
var r24 = ary24.map(function (item, index) {
  return item  2;
});
console.log(ary24, r24);
复制代码
相关文章
相关标签/搜索