ES6-Array
1 /* 2 * 数组解构赋值: 3 * ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这种被称为解构。 4 * 示例如下: 5 */ 6 var [a,b,c] = [1,2,3]; 7 console.log(a); //可以直接使用。 8 //本质上,这种写法属于模式匹配,只要等号两边的模式相同,左边的变量就会被赋予对应的值。 9 //如果解构不成功,变量的值就等于undefined 10 var [foo] = []; 11 console.log(foo); 12 var [bar,hoo] = [1]; 13 console.log(hoo); 14 //上边这两种都属于解构不成功 15 //下面情况属于不完全解构,但是会成功 16 var [m,n] = [1,2,3]; 17 console.log([m,n]); 18 19 //如果等号右边不是可以遍历的结构,那么将会报错: 20 // let [foo]=1;类似这种,因为转成对象后找不到Iterator接口。{}本身不具备Iterator接口。 21 //对于Set结构,也可以使用数组的解构赋值: 22 let [x,y,z] = new Set(["a","b","c"]); 23 console.log(x); 24 25 //解构赋值允许有默认值 26 var [foo = true] = []; 27 console.log(foo); 28 //ES6内部使用严格相等运算符(===), 判断一个位置是否有值。 29 //所以如果一个数组成员不严格等于undefined,默认值是不会生效的。 30 // var [foo = 1] = [k]; 31 console.log(foo); //默认值不生效,报错k没有定义 32 var [l = 1] = [undefined]; 33 console.log(l); //严格等于undefined的时候,默认值才生效。 34 //如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在生效用到的时候才会求值。 35 //默认值也可以引用结构赋值的其他变量,但该变量必须已经声明: 36 let [p = 1,q=p] = [2]; 37 console.log([p,q]); 38 39 //数组的扩展 40 /* 41 * Array.from()将两类对象转换为真正的数组:类似数组的对象和可遍历的对象 42 * 包括es6新增数据类型Set和Map。 43 * 下面是一个类似数组的对象,Array.from()将它转为真正的数组: 44 */ 45 let arrLike = { 46 "0":"a", 47 "1":"b", 48 "2":"c", 49 length:3 50 } 51 //es5的写法: 52 var arr1 = [].slice.call(arrLike); 53 console.log(arr1); 54 //es6 的写法 55 var arr2 = Array.from(arrLike); 56 console.log(arr2); 57 //实际应用中,常见的类似数组的对象是DOM操作返回的NodeList集合,以及函数内部arguments对象。 58 //Array.from都可以将它们转换为数组。 59 //nodelist对象 60 let ps = document.querySelectorAll("p"); 61 Array.from(ps).forEach(function(p){ 62 console.log(p); 63 }) 64 //arguments对象 65 function test(a,...rest){ 66 var args = Array.from(arguments); 67 console.log(args); 68 } 69 test(1,2,3,4,5,6); 70 //只要是部署了Iterator接口的数据,Array.from都可以将它转换为数组。 71 console.log(Array.from("hello")); 72 let nameSet = new Set(["a","b"]); 73 console.log(Array.from(nameSet)); 74 //如果参数是一个真正的数组,Array.from会返回一个一模一样的新数组。 75 //值得注意的是 扩展运算符(...)也可以将某些数据结构转为数组。 76 //arguments对象 77 function test2(){ 78 var args = [...arguments]; 79 console.log(args); 80 } 81 test2(2,4,5,6); 82 //nodelist对象 83 console.log([...document.querySelectorAll("p")]); 84 85 //任何有length属性的对象,都可以被Array.from转成数组,但扩展运算符在这时候不能转: 86 console.log(Array.from({length:3})); 87 console.log( [...{length:3}]); //实际上也转换成功了。 ??? 88 89 /* 90 * 对于没有部署的浏览器可以用Array.prototype.slice方法替代。 91 */ 92 const toArray = (() => 93 Array.from ? Array.from : obj=>[].slice.call(obj) 94 )(); 95 96 //Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理, 97 //将处理后的值放入返回的数组。 98 Array.from(arrLike,x=>x*x); 99 //等同于 100 Array.from(arrLike).map(x=>x*x); 101 102 console.log(Array.from([1,2,3],x=>x*x)); 103 104 //用途比较广,dom操作,到数组值得转换,到返回一组数据的数据类型。 105 function typesOf(){ 106 return Array.from(arguments,value=>typeof value) 107 } 108 console.log(typesOf("s",1,Number,[])) 109 110 //如果map函数里用到了this关键字,还可以传入Array.from的第三个参数,用来绑定this。 111 112 //只要有一个原始的数据结构,就可以对它的值进行处理,然后转成规范的数组,进而使用数组的方法。 113 console.log(Array.from({length:2},()=>"jack")); 114 //上面代码中,第一个参数,指定了第二个参数的运行次数,这种特性可以让该方法的方法变得非常灵活。 115 116 //另一个应用是将字符串转为数组,然后返回字符串的长度,这样可以正确处理各种Unicode字符,可以 117 //避免将大于\uFFFF的Unicode字符,算作两个字符的bug。 118 119 function countSymbols(string){ 120 return Array.from(string).length; 121 } 122 123 124 //Array.of()将一组值,转换为数组。 125 console.log(Array.of(3,11,8)); 126 console.log(Array.of(3)); 127 console.log(Array.of(3,11,8).length); 128 //这个方法的主要目标是弥补数组构造函数的不足。因为参数个数不同,会导致Array()的行为有差异。 129 console.log(Array()); //[] 130 console.log(Array(3)); //[,,] 131 console.log(Array(3,8,4)); //[3,8,4] 132 // 上面代码中,Array方法参数为0,1,3时候,返回结果都不一样,只有当参数个数不少于2个时,Array才会返回 133 //由参数组成的额数组,一个参数时,实际上是在指定数组长度。 134 135 //Array.of() 基本上可以用来替代Array或new Array(), 并且不存在由于参数不同而导致的重载。行为非常统一。 136 //Array.of()总是返回由参数值组成的数组。如果参数没有值,就返回一个空数组。 137 //Array.of()可以用下面的代码模拟实现: 138 function Arrayof(){ 139 return [].slice.call(arguments); 140 } 141 142 143 /* 144 * 数组实例的copyWithin 145 * 在当前的数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返当前数组,也就是说,使用这个方法,会修改当前数组。 146 * Array.prototype.copyWithin(target,start=0,end=this.length); 147 * 接收三个参数: 148 * target:从该位置开始替换数据; 149 * start:从该位置开始读取数据,默认为0,如果为负值,表示倒数。 150 * end:到该位置停止读取数据,默认等于数组长度。如果是负值,表示倒数。 151 * 这三个都应该是数值,如果不是,自动转换。 152 */ 153 console.log([1,2,3,4,5].copyWithin(0,3)); 154 //将3号位复制到0号位 155 console.log([].copyWithin.call({length:5,3:1},0,3)); 156 157 //不再举例 158 159 /* 160 * 数组实例的find()和findIndex() 161 * find()方法用于找出第一个符合条件的数组成员。它的参数是一个回调函数, 162 * 所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。 163 * 如果没有符合条件的成员,返回undefined。 164 */ 165 console.log([1,2,-5,7].find(x=>x<0)); //-5 166 console.log([1,5,10,15].find(function(value,index,arr){ 167 return value > 9; 168 })) //10 169 //上面代码中,find的回调函数有三个参数,值,索引,原数组。 170 171 //findIndex方法的用法与find方法非常类似,返回一个符合条件的数组成员的索引,都不符合就返回-1。 172 console.log([1,5,10,15].findIndex(function(value,index,arr){ 173 return value > 9; 174 })) //2 索引 175 //这两个方法都可以接受第二个参数,用来绑定回调函数的this对象。 176 //另外这两个方法都可以发现NaN,弥补了数组IndexOf方法的不足。 177 console.log([NaN].indexOf(NaN)) //-1 178 console.log([NaN].findIndex(y=>Object.is(NaN,y))); //0 179 /* 180 * 关于Object.is() 多数时候与"===" 等价, 181 * 但对于NaN、0、+0、 -0,则和 “===” 不同。 182 * 也就是用Object.is(NaN,NaN) //true 183 * Object.is(0,-0) //false 184 * Object.is(+0,-0) //false 185 */ 186 187 188 /* 189 * 数组实例的fill() 190 * 使用给定值,填充一个数组。相当于重写。 191 * 接受第二和第三个参数,用于指定填充的起始位置和结束位置(不包括结束的位置)。 192 */ 193 console.log([1,2,3].fill("a")); //[a,a,a] 194 console.log(new Array(3).fill(4)); //[4,4,4] 195 console.log([1,2,3,4,5,6].fill("a",2,4)) //[1,2,a,a,5,6] 196 197 198 /* 199 * 数组实例的entries(),keys(),values()用于遍历数组。 200 * 都返回一个Iterator对象,用for of循环,区别是 201 * keys()是对键名的遍历,values()是对键值的遍历,entries是对键值对的遍历。 202 */ 203 for(let index of ["a","b"].keys()){ 204 console.log("index:",index); 205 } 206 for(let ele of [1,2,3]){ 207 //values这个方法好像找不到了。应该换成了这样的写法 208 console.log("value:",ele); 209 } 210 for(let [index,ele] of ["a","b"].entries()){ 211 console.log("key-val:",index,ele); 212 } 213 //下面这个倒是可以用的,但是是绑定在Object上的。 214 var obj = {"a":"html","b":"javascript"}; 215 console.log(Object.values(obj)); 216 //如果不使用for of循环,可以用手动的next进行遍历: 217 let letter = ["a","b","v"]; 218 let entries = letter.entries(); 219 console.log(entries.next().value); 220 console.log(entries.next().value); 221 console.log(entries.next().value); 222 console.log(entries.next().value); //超过了长度就是undefined 223 224 /* 225 * 数组实例的includes(),返回一个布尔值,表示某个数组是否包含给定的值,与字符串的 226 * includes类似,属于es7,但babel已经支持。 227 */ 228 console.log([1,2,3].includes(2)); //true 229 console.log([1,2,3].includes(4)); //false 230 console.log([1,2,NaN].includes(NaN)); //true 231 //该方法的第二个参数表示搜索的起始位置,默认为0,如果第二个参数为负数, 232 //表示倒数,如果这是它大于数组的长度,则会重置为从0开始。 233 //没有这个方法之前,都是用数组的indexOf方法,检查是否包含某个值。 234 //indexOf的缺点:不够语义化,他要找到参数出现的第一个位置,所以要和-1比较, 235 // 内部使用===判断,对NaN误判。 236 console.log([NaN].includes(NaN)); //true 237 //下面的代码检查当前环境是否支持该方法,如果不支持,部署一个简易版本: 238 const contains = (()=> 239 Array.prototype.includes?(arr,value)=>arr.includes(value) 240 :(arr,value)=>arr.some(el=>el===value) 241 )(); 242 console.log(contains(["foo","baz"],"baz")); 243 /* 244 *另外,Map和Set数据结构有一个has方法,需要注意与includes区分。 245 * Map的has方法,用来查找键名的。 246 * Set的has方法,用来查找值的。 247 */ 248 249 250 /* 251 * 数组的空位: 252 * 空位不是undefined,一个位置的值等于undefined,依然是有值的。 253 * 空位是米有任何值的。 254 */ 255 console.log( 0 in [undefined]); //true 256 console.log( 0 in [,]); //false 257 /* 258 * 上面代码说明,第一个数组的0号位置是有值的,第二个数组的0号位是没有值的。 259 * es5对空位的处理很不一致,大多数情况,跳过空位。 260 * forEach(),filter(),every(),some()都会跳过空位。 261 * map()会跳过空位,但会保留这个值 262 * join()和toString()会将空位视为undefined,而undefined和null会被 263 * 处理成空字符串。 264 * 265 * es6明确将空位转为undefined。 266 * Array.from会将数组的空位转为undefined,也就是不会忽略空位。 267 */ 268 console.log(Array.from(["a",,"b"])); //[a,undefined,b] 269 //扩展运算符也将空位转为undefined 270 console.log([...["a",,"b"]]); //[1,undefined,2] 271 //上面代码实测的时候,结果是[a,2:b]; 并没有undefined。
依赖文件地址:https://github.com/chanceLe/ES6-Basic-Syntax/tree/master/js