数组方法

1.1 concat

数组合并的方法

  1. var arr1 = ['a', 'b', 'c'],
  2. arr2 = ['d', 'e', 'f'];
  3. var arr3 = arr1.concat(arr2);
  4. var arr4 = arr2.concat(arr1);
  5. console.log(arr3);//['a', 'b', 'c', 'd', 'e', 'f']
  6. console.log(arr4);//['d', 'e', 'f', 'a', 'b', 'c']

1.2 toString

数组转字符串

  1. var arr5 = ['a', 'b', 'c', 'd'],
  2. arr6 = [1, 2, 3, 4, 5, 6, 7];
  3. console.log(arr5.toString());//a,b,c,d
  4. console.log(arr6.toString());//1,2,3,4,5,6,7

1.3 slice

slice(start开始元素的下标,end结束截取的位置之前)

  1. var arr7 = ['a', 'b', 'c', 'd', 'e', 'f'];
  2. console.log(arr7.slice(1));//['b', 'c', 'd','e', 'f'],从下标为1的位置截取,第二个参数不传,就截取到最后,且包含下标为1的值,是闭区间
  3. console.log(arr7.slice(1, 4));//['b', 'c', 'd'],第二个值就是结束截取的位置之前
  4. console.log(arr7.slice(-3, 5));//['d', 'e']
  5. console.log(arr7.slice(-3, -2));//['d']

1.4 join

转字符串,参数里面填什么,数组的元素就会以填写的值分割

  1. var arr8 = ['a', 'b', 'c', 'd'];
  2. console.log(arr8.join(), arr8.toString());//a,b,c,d a,b,c,d join方法不填参数的时候和toString方法是一样的
  3. console.log(arr8.join(''));//abcd

1.5 split

字符串转数组,第一个参数必须要是真正的分割符才能分割成功,第二个参数是截取的长度

  1. var arr9 = arr8.join('-');
  2. console.log(arr9.split('-'));//['a', 'b', 'c', 'd']
  3. console.log(arr9.split(''));//['a', '-', 'b', '-', 'c', '-', 'd']
  4. console.log(arr9.split('-', 3));//['a', 'b', 'c']

2. 类数组

  1. function test(){
  2. console.log(arguments);//Arguments(6) [1, 2, 3, 4, 5, 6, callee: ƒ, Symbol(Symbol.iterator): ƒ]
  3. }
  4. test(1, 2, 3, 4, 5, 6);

但是再给这个数组使用push方法

  1. function test(){
  2. arguments.push(7);
  3. console.log(arguments);//arguments.push is not a function,报错,push并不是一个方法
  4. }
  5. test(1, 2, 3, 4, 5, 6);

再试另外一种,有三个div

  1. var oDiv = document.getElementsByTagName('div');
  2. console.log(oDiv);//HTMLCollection(3) [div, div, div]
  3. oDiv.push(4);
  4. console.log(oDiv);//oDiv.push is not a function,报错,push不是一个方法

实际上证明了前面的例子里的arguments并没有继承Array.prototype,因为它根本没有push方法,所以这两个例子打印的数组并不是真正的Array,实际是上它们是类数组。类数组并不是真正意义上的数组,它是类似于数组的对象。
类数组与数组相比较,都有length属性,都有原型,但是类数组的原型是Object,数组的原型是Array。

2.1 模拟类数组

  1. var obj = {
  2. '0': 1,
  3. '1': 2,
  4. '2': 3,
  5. '3': 4,
  6. '4': 5,
  7. '5': 6,
  8. 'length': 6,
  9. 'splice': Array.prototype.splice,//加了这一步,打印的时候尖括号就变成了中括号
  10. 'push': Array.prototype.push//继承了push方法以后,不仅能用,length属性也会自动增加
  11. }
  12. obj.push(7);
  13. console.log(obj);//Object(7) [1, 2, 3, 4, 5, 6, 7, splice: ƒ, push: ƒ]

同理,splice和push方法也可以挂在Object原型上面也是一样的。

  1. var obj = {
  2. '0': 1,
  3. '1': 2,
  4. '2': 3,
  5. '3': 4,
  6. '4': 5,
  7. '5': 6,
  8. 'length': 6
  9. }
  10. Object.prototype.push = Array.prototype.push;
  11. Object.prototype.splice = Array.prototype.splice;
  12. obj.push(7);
  13. console.log(obj);//Object(7) [1, 2, 3, 4, 5, 6, 7, splice: ƒ, push: ƒ]

这个push实现的原理是什么,模拟实现这个方法:

  1. Array.prototype.push = function(elem){
  2. this[this.length] = elem;
  3. this.length ++;
  4. }

3 面试题

3.1 例

  1. var obj2 = {
  2. '2': 3,
  3. '3': 4,
  4. 'length': 2,
  5. 'splice': Array.prototype.splice,
  6. 'push': Array.prototype.push
  7. }
  8. obj2.push(1);
  9. obj2.push(2);
  10. console.log(obj2);//Object(4) [empty × 2, 1, 2, splice: ƒ, push: ƒ]
  11. //第一次push的时候length为1,obj2['2'] = 1,第二次执行的时候length为2,obj2['3'] = 2,但是执行了两次,数组中的两项被替换了,又有长度,所以,前两项是空

3.2 例

重点,点运算符的优先级比new关键字的优先级要高,括号的优先级比点运算符大。

  1. function Foo(){
  2. getName = function(){
  3. console.log(1);
  4. }
  5. return this;
  6. }
  7. Foo.getName = function(){
  8. console.log(2);
  9. }
  10. Foo.prototype.getName = function(){
  11. console.log(3);
  12. }
  13. var getName = function(){
  14. console.log(4);
  15. }
  16. function getName(){
  17. console.log(5);
  18. }
  19. Foo.getName();//2,执行自己的方法,和Foo没关系
  20. getName();//4,预编译的时候GO保存了一个变量getName,先赋值undefined,然后找函数声明,undefined变成了function getName(){console.log(5);}。最后执行的时候变量又赋了值变成匿名函数的function(){console.log(4);}
  21. Foo().getName();//1
  22. getName();//1,上一步function执行的时候,里面的getName没有经过var声明,就被带到全局去了,所以getName()是1
  23. new Foo.getName();//2,点运算符的优先级比new关键字的优先级要高,所以是先执行的Foo.getName(),再new 2,但是new一个数字没有意义的,相当于new没写
  24. new Foo().getName();//3,括号的优先级比点运算符大,所以Foo()先执行,执行后立马就要new,然后自身并没有this.getName,但是原型上有,所以是3
  25. new new Foo().getName();//3,同上,已经是3了,再去new一个数字3并没有意义,所以还是3

3.3 例

  1. var person = {
  2. '0': '张小一',
  3. '1': '张小二',
  4. '2': '张小三',
  5. 'name': '张三',
  6. 'age': 32,
  7. 'weigth': 140,
  8. 'height': 180,
  9. 'length': 3//注意length值是3
  10. }
  11. Object.prototype.push = Array.prototype.push;
  12. Object.prototype.splice = Array.prototype.splice;
  13. console.log(person[1]);//张小二
  14. console.log(person.weigth);//140
  15. console.log(person.length);//3
  16. console.log(person);//Object(3) ['张小一', '张小二', '张小三', name: '张三', age: 32, weigth: 140, height: 180]

既有数组的特性,又有对象的特性,还能遍历

  1. for(var key in person){
  2. if(person.hasOwnProperty(key)){
  3. console.log(key);
  4. }
  5. }

总结,类数组一定要有下标对应的值,一定要有length属性,如果有用到push可以去Array.prototype上去继承

作业

判断闰年(1.整除4,并且不能整除100 2.能整除100)

  1. var year = window.prompt('请输入年份');
  2. function isLeapYear(year){
  3. if((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0){
  4. return '是闰年';
  5. }else{
  6. return '不是闰年';
  7. }
  8. }
  9. console.log(isLeapYear(year));