最近一直在努力的恶补javascript中的各种知识,比如说闭包,作用域,继承,构造函数,变量,内置对象等概念。同时,也在学习着ES6的新知识。最近想给大家分享的就是数组实例方法的练习以及如何去扩展一个数组方法。
以下的分享会分为如下内容
1.数组实例方法的练习
1.1:reduce()
1.2:map()
1.3:sort()
1.4:slice()
1.5:push()
1.6:实例方法习题
2.数组方法的扩展
1.数组实例方法的练习
首先,我们应该知道数组实例方法有哪些。
console.log(Object.getOwnPropertyNames(Array)); // ["isArray", "concat", "lastIndexOf", "indexOf", "forEach", "map", "filter", "every", "some", "reduce", "reduceRight", "join", "reverse", "sort", "push", "pop", "shift", "unshift", "splice", "slice", "from", "of", "prototype", "length", "name"]
上面代码中,使用对象的原生方法getOwnPropertyNames方法来返回对象实例的所有方法。
下面对一些实例方法做一些简单的介绍。
1.1:reduce方法
reduce
方法和reduceRight
方法都是依次处理数组的每个成员,最终累计为一个值。它们的差别是,reduce
是从左到右处理(从第一个成员到最后一个成员),reduceRight
则是从右到左(从最后一个成员到第一个成员),其他完全一样。
这两个方法的第一个参数都是一个函数。该函数接受以下四个参数。
累积变量,默认为数组的第一个成员
当前变量,默认为数组的第二个成员
当前位置(从0开始)
原数组
只有前两个才是必须传入的,reduce方法最常用的就是用于数组元素的相加,然后返回累加的值。
var arr = [1,2,3,4,5]; function sum(first,last){ return first+last; } console.log(arr.reduce(sum))
针对reduce()方法,我重新写了一篇详细的文章,传送门:reduce()方法解析
1.2:map()
map
方法对数组的所有成员依次调用一个函数,根据函数结果返回一个新数组。要注意的是,map方法返回一个新数组,而原数组是没有发生变化的。
var arr = [1,2,3,4,5]; var newArr = arr.map(function(value, index) { return value+1; }); console.log(newArr); // [2, 3, 4, 5, 6] console.log(arr); // [1, 2, 3, 4, 5]
上面代码中,arr
数组的所有成员都加上1,组成一个新数组返回,原数组没有变化。
map
方法接受一个函数作为参数。该函数调用时,map
方法会将其传入三个参数,分别是当前成员、当前位置和数组本身。
1.3:sort()
sort
方法对数组成员进行排序,默认是按照ascii字母顺序排序。排序后,原数组将被改变。
var arr1 = [5,6,7,2,6,8,1]; console.log(arr1.sort()); //[1, 2, 5, 6, 6, 7, 8] console.log(arr1); //[1, 2, 5, 6, 6, 7, 8] var arr2 = [1,2,3,11,22,33]; console.log(arr2.sort()); //[1, 11, 2, 22, 3, 33]6 console.log(arr2); //[1, 11, 2, 22, 3, 33]
如果要让sort方法正常排序,可以传入一个函数。函数带有两个参数,表示进行比较的两个元素。
var arr2 = [1,2,3,11,22,33]; console.log(arr2.sort(function(a,b){ return a - b; })); // [1, 2, 3, 11, 22, 33]
1.4:slice()
slice
方法用于提取原数组的一部分,返回一个新数组,原数组不变。它的第一个参数为起始位置(从0开始),第二个参数为终止位置(但该位置的元素本身不包括在内)。如果省略第二个参数,则一直返回到原数组的最后一个成员。
var arr = [1,2,3,4,5]; console.log(arr.slice(0)); // [1, 2, 3, 4, 5] console.log(arr.slice(1,2)); //[2] console.log(arr.slice(2,5)); //[3, 4, 5] console.log(arr.slice(3)); //[4, 5] console.log(arr); //[1, 2, 3, 4, 5]
如果slice为负数,则表示倒数计算的位置。
var arr = [1,2,3,4,5]; console.log(arr.slice(-3));//[3, 4, 5] console.log(arr.slice(-3,-1));// [3, 4] console.log(arr); // [1, 2, 3, 4, 5]
注意,传入负数时,index值是从-1开始计算的。而传入正数时,index值是从0开始计算的。
1.5:push()
push
方法用于在数组的末端添加一个或多个元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。
var arr = [1,2,3,4,5]; arr.push(6); console.log(arr); // [1, 2, 3, 4, 5, 6] arr.push([7,8]); console.log(arr); // [1, 2, 3, 4, 5, 6, [7, 8]] arr.push(true); console.log(arr); // [1, 2, 3, 4, 5, 6, [7, 8], true]
1.6:实例方法习题
★数组中去掉最大值,去掉最小值,其余元素进行相加。
function sumArray(array) { if (array === null || array.length < 2) { return 0; } else { array = array.sort(function(a, b) { return a - b; }) var sum = 0; for (var i = 1; i < array.length - 1; i++) { sum += array[i]; } return sum; } } console.log(sumArray([1,2,3,4,5,9]));
上面代码中,使用了sort方法对数组进行排序。然后巧妙地使用for循环,让变量初始化的值等于第二个元素,让循环的长度值等于数组的长度减一,这样就实现了去掉一个最小值和最大值,剩余值进行相加的方法。
★将字符串中的元素分隔,首字符大写,然后再按照index值加入相同小写字母。比较难描述,看例子,就很容易理解。
function accum(s) { var arr = s.split(''); return arr.map(function(value, index) { var upper = value.toUpperCase(); for (var i = 1; i <= index; i++) { upper += value.toLowerCase(); } return upper; }).join('-') } console.log(accum('keith')); //'K-Ee-Iii-Tttt-Hhhhh' console.log(accum('studyhard')); //'S-Tt-Uuu-Dddd-Yyyyy-Hhhhhh-Aaaaaaa-Rrrrrrrr-Ddddddddd'
上面代码中,使用字符串对象的实例方法先将字符串分割,接着用map方法循环每一个字符。要注意的是map方法会返回一个新数组,不改变原数组,最后使用字符串对象实例方法join方法将字符串以'-'的形式分割。
★将平均数与个人成绩进行比较。如果大于平均数,则返回true;否则为false。
function betterThanAverage(classPoints, yourPoints) { var len=classPoints.length; var sum=0; for (var i = 0; i < classPoints.length; i++) { sum+=classPoints[i]; } if (yourPoints>(sum/len)) { return true; } else{ return false; } } console.log(betterThanAverage([62,83,74,66,99,100],80)); //false
上面代码中,先获取数组的长度,然后将数组进行相加,再除以长度值,最后进行比较。
★当数组中的数为正数时,计算正数的个数;当数组中的数为负数时,将所有负数相加。注意,对负数和正数的处理方式不同。
function countPositivesSumNegatives(input) { if (input===null||input.length===0) { return []; } else{ var count = 0; var sum = 0; for(var i = 0;i < input.length; i++){ if (input[i]<0) { sum+=input[i]; } else if(input[i]!==0){ count+=1; } } return [count,sum]; } } console.log(countPositivesSumNegatives([1, 2, 3, 4, 5, 6, 7, 8, 9, 131,10, -11, -12, -13, -14, -15])); //[11, -65]
上面代码中,对数组进行了简单的判断。使用for循环再对数组的正负值进行判断。
★创建一个函数,这个函数有2个参数,第一个参数为有x个值得数组,第二个参数为数组的长度。功能就是将最后x个值进行相加然后传入数组末尾。有两种解决方法,第二种方法采用了es6的方法箭头函数。同样,看实例比较容易理解题目的意思。
function Sum(first,last){ return first+last; } function Xbonacci(signature,n){ var indexArr = signature.length; for (var i = 0; i < n - indexArr; i++) { var sum = signature.slice(-indexArr).reduce(Sum); signature.push(sum); } return signature.slice(0,n); } console.log(Xbonacci([0,0,0,0,1],10)); //[0, 0, 0, 0, 1, 1, 2, 4, 8, 16] console.log(Xbonacci([1,1],10)); // [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] console.log(Xbonacci([1,0,0,0,0,0,1],10)); // [1, 0, 0, 0, 0, 0, 1, 2, 3, 6] console.log(Xbonacci([0, 19, 16, 3, 6, 14, 17, 14, 15, 20, 8, 19, 7, 8, 12, 14, 11, 11, 18],4)); // [0, 19, 16, 3]
const Xbonacci = (sig, n) => { let len = sig.length; for (let i = len; i < n; i++) sig[i] = sig.slice(i - len).reduce((a, b) => a + b); return sig.slice(0, n); }
上面代码中,将[0,0,0,0,1]相加得2,然后将2push到数组中;将[0,0,0,1,2]相加4,然后将4push到数组中,以此类推。最后返回处理后的数组。
个人认为,熟悉数组实例方法最好的办法就是去尝试做这些题目,每一次做的题目对数组的方法都会有一个新的理解,每一次理解都会让你意识到哪一个方法需要在哪一种场景使用,而哪一个方法在某个场景使用是不合适的。光看不练对知识的掌握程度总是稍显不足。
2.数组方法的扩展
数组的实例方法中,没有给我们提供数组求和,求平方,求立方,求平均数,求偶数元素,求奇数元素的方法。所以我们需要去扩展数组的方法以方便实际工作中的开发。
Array.prototype.square = function () { return this.map(function(n) { return n*n; }); } Array.prototype.cube = function () { return this.map(function(n) { return n*n*n; }); } Array.prototype.average = function () { return this.sum() / this.length; } Array.prototype.sum = function () { return this.reduce(function(a, b) { return a + b; }, 0); } Array.prototype.even = function () { return this.filter(function(item) { return 0 === item % 2; }); } Array.prototype.odd = function () { return this.filter(function(item) { return 0 !== item % 2; }); } var arr = [1,2,3,4,5,6]; console.log(arr.square()); // [1, 4, 9, 16, 25, 36] console.log(arr.cube()); // [1, 8, 27, 64, 125, 216] console.log(arr.average()); // 3.5 console.log(arr.sum()); console.log(arr.even()); // [2, 4, 6] console.log(arr.odd()); // [1, 3, 5]
上面代码中,为构造函数Array的原型对象添加square,cube等方法的目的是让所有实例都可以共享这些方法。而prototype属性的作用也就是让所有实例对象可以共享属性和方法。
如果想理解数组方法的扩展,需要知道的知识有:
1.原型对象和构造函数的关系。
2.this关键字的指向性问题。
如果想要详细了解,可以前往这这些文章。Javascript中prototype属性的详解,javascript之 this 关键字详解,Javascript 中构造函数与new命令的密切关系,深入理解Javascript中构造函数和原型对象的区别 等。
完。
感谢大家的阅读。