判断是否是数组的几种方式
在 ES5 提供的方法之前,我们至少有如下 5 种方式去判断一个变量是否为数组。
var a = []; // 1.基于instanceof a instanceof Array; // 2.基于constructor a.constructor === Array; // 3.基于Object.prototype.isPrototypeOf Array.prototype.isPrototypeOf(a); // 4.基于getPrototypeOf Object.getPrototypeOf(a) === Array.prototype; // 5.基于Object.prototype.toString Object.prototype.toString.apply(a) === '[object Array]';
ES6 之后新增了一个 Array.isArray()
方法,能直接判断数据类型是否为数组
手写一个isArray方法
if(!Array.isArray){ Array.isArray = function(arg){ return Object.prototype.toString.cell(arg) === "[object Array]"; } }
数组改变自身的方法
会改变自身值的方法一共有 9 个,分别为 pop
、push
、reverse
、shift
、sort
、splice
、unshift
,以及两个 ES6 新增的方法 copyWithin
和 fill
// 1.pop方法:删除最后一个元素,返回被删除元素,改变自身 var array = ["cat", "dog", "cow", "chicken", "mouse"]; var item = array.pop(); console.log(array); // ["cat", "dog", "cow", "chicken"] console.log(item); // mouse // 2.push方法:在数组尾部添加元素,改变自身,返回改变后的长度 var array = ["football", "basketball", "badminton"]; var i = array.push("golfball"); console.log(array); // ["football", "basketball", "badminton", "golfball"] console.log(i); // 4 // 3.reverse方法:翻转数组,改变自身,返回改变后的数组 var array = [1,2,3,4,5]; var array2 = array.reverse(); console.log(array); // [5,4,3,2,1] console.log(array2===array); // true // 4.shift方法:删除第一个元素,返回被删除的元素 var array = [1,2,3,4,5]; var item = array.shift(); console.log(array); // [2,3,4,5] console.log(item); // 1 // 5.unshift方法:添加元素,添加到最前面,返回最新长度 var array = ["red", "green", "blue"]; var length = array.unshift("yellow"); console.log(array); // ["yellow", "red", "green", "blue"] console.log(length); // 4 // 6.sort方法:排序,安装ascll码排序 var array = ["apple","Boy","Cat","dog"]; var array2 = array.sort(); console.log(array); // ["Boy", "Cat", "apple", "dog"] console.log(array2 == array); // true // 7.splice方法:删除或替换元素。第一个值:索引,第二个值:个数,第三个值:替换元素。没有第三个值就是删除,有就是替换 var array = ["apple","boy"]; var splices = array.splice(1,1); console.log(array); // ["apple"] console.log(splices); // ["boy"] // 8.copyWithin方法:从数组的指定位置拷贝元素到数组的另一个指定位置中 var array = [1,2,3,4,5]; var array2 = array.copyWithin(0,3); console.log(array===array2,array2); // true [4, 5, 3, 4, 5] // 9.fill方法:用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引 var array = [1,2,3,4,5]; var array2 = array.fill(10,0,3); console.log(array===array2,array2); // true [10, 10, 10, 4, 5], 可见数组区间[0,3]的元素全部替换为10
不改变自身的方法
// 1.concat方法:合并数组 var array = [1, 2, 3]; var array2 = array.concat(4,[5,6],[7,8,9]); console.log(array2); // [1, 2, 3, 4, 5, 6, 7, 8, 9] console.log(array); // [1, 2, 3], 可见原数组并未被修改 // join方法:数组转字符串 var array = ['We', 'are', 'Chinese']; console.log(array.join()); // "We,are,Chinese" console.log(array.join('+')); // "We+are+Chinese" // slice方法:截取指定位置元素:返回被截取的数组 var array = ["one", "two", "three","four", "five"]; console.log(array.slice()); // ["one", "two", "three","four", "five"] console.log(array.slice(2,3)); // ["three"] // toString方法 var array = ['Jan', 'Feb', 'Mar', 'Apr']; var str = array.toString(); console.log(str); // Jan,Feb,Mar,Apr // tolocalString方法 var array= [{name:'zz'}, 123, "abc", new Date()]; var str = array.toLocaleString(); console.log(str); // [object Object],123,abc,2016/1/5 下午1:06:23 // indexOf方法 var array = ['abc', 'def', 'ghi','123']; console.log(array.indexOf('def')); // 1 // includes方法 var array = [-0, 1, 2]; console.log(array.includes(+0)); // true console.log(array.includes(1)); // true var array = [NaN]; console.log(array.includes(NaN)); // true
类数组
JS 中一直存在一种类数组的对象,它们不能直接调用数组的方法,但是又和数组比较类似,在某些特定的编程场景中会出现
主要有以下几种:
- 函数里面的参数对象 arguments;
- 用 getElementsByTagName/ClassName/Name 获得的 HTMLCollection;
- 用 querySelector 获得的 NodeList。
函数中使用的 arguments,它的对象只定义在函数体中,包括了函数的参数和其他属性。我们通过一段代码来看下 arguments 的使用方法,如下所示。
function foo(name, age, sex) { console.log(arguments); console.log(typeof arguments); console.log(Object.prototype.toString.call(arguments)); } foo('jack', '18', 'male');
从结果中可以看到,typeof 这个 arguments 返回的是 object,通过 Object.prototype.toString.call 返回的结果是 '[object arguments]',可以看出来返回的不是 '[object array]',说明 arguments 和数组还是有区别的。
length 属性很好理解,它就是函数参数的长度,从打印出的代码也可以看得出来。另外可以看到 arguments 不仅仅有一个 length 属性, 还有一个 callee 属性,我们接下来看看这个 callee 是干什么的,代码如下所示。
function foo(name, age, sex) { console.log(arguments.callee); } foo('jack', '18', 'male');
从控制台可以看到,输出的就是函数自身,如果在函数内部直接执行调用 callee 的话,那它就会不停地执行当前函数,直到执行到内存溢出
遍历数组
forEach
forEach()
遍历数组forEach()
方法对数组的每个元素执行一次提供的函数。- 没有返回值
- 不能中止或跳出 forEach 循环 ,break/return也不行
var arr1 = [1, 2, 3, 4, 5] //item当前值,索引值,数组 var solt = arr1.forEach((item,index,arr) => { console.log(item,index,arr) }) console.log(solt) // undefined //可以直接写 arr1.forEach((item,index,arr) => { //todo })
map
map()
方法创建一个数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果map
不修改调用它的原数组本身(当然可以在 callback 执行时改变原数组)。map
方法会给原数组中的每个元素都按顺序调用一次callback
函数。callback
每次执行后的返回值(包括undefined
)组合起来形成一个新数组。callback
函数只会在有值的索引上被调用;那些从来没被赋过值或者使用delete
删除的索引则不会被调用。
let arr = [1, 2, 3, 4, 5] const newArr = arr.map(item => { return item+ 10; }) console.log(newArr);//[11, 12, 13, 14, 15]
filter
filter()
方法创建一个新数组,其包含通过所提供函数测试的 所有元素filter
不会改变原数组,它返回过滤后的新数组。
var arr = [12, 5, 8, 130, 44] var filtered = arr.filter(function(v) { return v >= 10 }) console.log(filtered) // [12, 130, 44] 复制代码
遍历对象
for...in
- 循环遍历对象自身的和继承的可枚举的属性(不含 Symbol 属性)
let pStr = Symbol('pStr'); let subStr = Symbol('subStr'); let obj = { subId: 100, [subStr]: '子级的Symbol类型', subName: 'old', subAge: 20, addr: '北京市朝阳区' } for (const key in obj) { console.log(key + ' --- ' + obj[key]); } //subId --- 100 //subName --- old //subAge --- 20 //addr --- 北京市朝阳区
Object.keys(obj)
- 返回一个数组,包括对象自身的所有可枚举属性(不含继承的和Symbol 属性)
let pStr = Symbol('pStr'); let subStr = Symbol('subStr'); let obj = { subId: 100, [subStr]: '子级的Symbol类型', subName: 'xiaoliu', subAge: 20, addr: '北京市朝阳区' } for (const key of Object.keys(obj)) { console.log(key + ' --- ' + obj[key]); } //subId --- 100 //subName --- xiaoliu //subAge --- 20 //addr --- 北京市朝阳区
Object.getOwnPropertyNames(obj)
- 返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但包含不可枚举属性)
let pStr = Symbol('pStr'); let subStr = Symbol('subStr'); let pObj = { pId: 1, [pStr]: '父级的Symbol类型', pName: 'zhangsan', } let obj = { subId: 100, [subStr]: '子级的Symbol类型', subName: 'xiaoliu', subAge: 20, addr: '北京市朝阳区' } Object.setPrototypeOf(obj, pObj) for (const key of Object.getOwnPropertyNames(obj)) { console.log(key + ' --- ' + obj[key]); }
Object.entries()
- 返回对象所有键值对组成的数组,再结合
forEach
即可完成遍历。
const obj = { a: 1, b: 2 }; for (let [key, value] of Object.entries(obj)) { console.log(key, value); } // a 1 // b 2
Object.keys()
获取键,Object.values()
获取值