数组方法
1.1 concat
数组合并的方法
var arr1 = ['a', 'b', 'c'],arr2 = ['d', 'e', 'f'];var arr3 = arr1.concat(arr2);var arr4 = arr2.concat(arr1);console.log(arr3);//['a', 'b', 'c', 'd', 'e', 'f']console.log(arr4);//['d', 'e', 'f', 'a', 'b', 'c']
1.2 toString
数组转字符串
var arr5 = ['a', 'b', 'c', 'd'],arr6 = [1, 2, 3, 4, 5, 6, 7];console.log(arr5.toString());//a,b,c,dconsole.log(arr6.toString());//1,2,3,4,5,6,7
1.3 slice
slice(start开始元素的下标,end结束截取的位置之前)
var arr7 = ['a', 'b', 'c', 'd', 'e', 'f'];console.log(arr7.slice(1));//['b', 'c', 'd','e', 'f'],从下标为1的位置截取,第二个参数不传,就截取到最后,且包含下标为1的值,是闭区间console.log(arr7.slice(1, 4));//['b', 'c', 'd'],第二个值就是结束截取的位置之前console.log(arr7.slice(-3, 5));//['d', 'e']console.log(arr7.slice(-3, -2));//['d']
1.4 join
转字符串,参数里面填什么,数组的元素就会以填写的值分割
var arr8 = ['a', 'b', 'c', 'd'];console.log(arr8.join(), arr8.toString());//a,b,c,d a,b,c,d join方法不填参数的时候和toString方法是一样的console.log(arr8.join(''));//abcd
1.5 split
字符串转数组,第一个参数必须要是真正的分割符才能分割成功,第二个参数是截取的长度
var arr9 = arr8.join('-');console.log(arr9.split('-'));//['a', 'b', 'c', 'd']console.log(arr9.split(''));//['a', '-', 'b', '-', 'c', '-', 'd']console.log(arr9.split('-', 3));//['a', 'b', 'c']
2. 类数组
function test(){console.log(arguments);//Arguments(6) [1, 2, 3, 4, 5, 6, callee: ƒ, Symbol(Symbol.iterator): ƒ]}test(1, 2, 3, 4, 5, 6);
但是再给这个数组使用push方法
function test(){arguments.push(7);console.log(arguments);//arguments.push is not a function,报错,push并不是一个方法}test(1, 2, 3, 4, 5, 6);
再试另外一种,有三个div
var oDiv = document.getElementsByTagName('div');console.log(oDiv);//HTMLCollection(3) [div, div, div]oDiv.push(4);console.log(oDiv);//oDiv.push is not a function,报错,push不是一个方法
实际上证明了前面的例子里的arguments并没有继承Array.prototype,因为它根本没有push方法,所以这两个例子打印的数组并不是真正的Array,实际是上它们是类数组。类数组并不是真正意义上的数组,它是类似于数组的对象。
类数组与数组相比较,都有length属性,都有原型,但是类数组的原型是Object,数组的原型是Array。
2.1 模拟类数组
var obj = {'0': 1,'1': 2,'2': 3,'3': 4,'4': 5,'5': 6,'length': 6,'splice': Array.prototype.splice,//加了这一步,打印的时候尖括号就变成了中括号'push': Array.prototype.push//继承了push方法以后,不仅能用,length属性也会自动增加}obj.push(7);console.log(obj);//Object(7) [1, 2, 3, 4, 5, 6, 7, splice: ƒ, push: ƒ]
同理,splice和push方法也可以挂在Object原型上面也是一样的。
var obj = {'0': 1,'1': 2,'2': 3,'3': 4,'4': 5,'5': 6,'length': 6}Object.prototype.push = Array.prototype.push;Object.prototype.splice = Array.prototype.splice;obj.push(7);console.log(obj);//Object(7) [1, 2, 3, 4, 5, 6, 7, splice: ƒ, push: ƒ]
这个push实现的原理是什么,模拟实现这个方法:
Array.prototype.push = function(elem){this[this.length] = elem;this.length ++;}
3 面试题
3.1 例
var obj2 = {'2': 3,'3': 4,'length': 2,'splice': Array.prototype.splice,'push': Array.prototype.push}obj2.push(1);obj2.push(2);console.log(obj2);//Object(4) [empty × 2, 1, 2, splice: ƒ, push: ƒ]//第一次push的时候length为1,obj2['2'] = 1,第二次执行的时候length为2,obj2['3'] = 2,但是执行了两次,数组中的两项被替换了,又有长度,所以,前两项是空
3.2 例
重点,点运算符的优先级比new关键字的优先级要高,括号的优先级比点运算符大。
function Foo(){getName = function(){console.log(1);}return this;}Foo.getName = function(){console.log(2);}Foo.prototype.getName = function(){console.log(3);}var getName = function(){console.log(4);}function getName(){console.log(5);}Foo.getName();//2,执行自己的方法,和Foo没关系getName();//4,预编译的时候GO保存了一个变量getName,先赋值undefined,然后找函数声明,undefined变成了function getName(){console.log(5);}。最后执行的时候变量又赋了值变成匿名函数的function(){console.log(4);}Foo().getName();//1getName();//1,上一步function执行的时候,里面的getName没有经过var声明,就被带到全局去了,所以getName()是1new Foo.getName();//2,点运算符的优先级比new关键字的优先级要高,所以是先执行的Foo.getName(),再new 2,但是new一个数字没有意义的,相当于new没写new Foo().getName();//3,括号的优先级比点运算符大,所以Foo()先执行,执行后立马就要new,然后自身并没有this.getName,但是原型上有,所以是3new new Foo().getName();//3,同上,已经是3了,再去new一个数字3并没有意义,所以还是3
3.3 例
var person = {'0': '张小一','1': '张小二','2': '张小三','name': '张三','age': 32,'weigth': 140,'height': 180,'length': 3//注意length值是3}Object.prototype.push = Array.prototype.push;Object.prototype.splice = Array.prototype.splice;console.log(person[1]);//张小二console.log(person.weigth);//140console.log(person.length);//3console.log(person);//Object(3) ['张小一', '张小二', '张小三', name: '张三', age: 32, weigth: 140, height: 180]
既有数组的特性,又有对象的特性,还能遍历
for(var key in person){if(person.hasOwnProperty(key)){console.log(key);}}
总结,类数组一定要有下标对应的值,一定要有length属性,如果有用到push可以去Array.prototype上去继承
作业
判断闰年(1.整除4,并且不能整除100 2.能整除100)
var year = window.prompt('请输入年份');function isLeapYear(year){if((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0){return '是闰年';}else{return '不是闰年';}}console.log(isLeapYear(year));
