Array
MDN定义 : JavaScript的 Array 对象是用于构造数组的全局对象,数组是类似于列表的高阶对象。
创建数组的几种方法
let a = [1,2]//直接赋值
let a = new Array(4)//构造函数赋值,定义数组长度,或者不给出具体长度都可以
let a = new Array('apple' , 'bear' , 'banana')//构造函数赋值,直接给出数组内容
Array常见API
操作数组的方法分为纯函数方法与非纯函数方法,纯函数方法不会改变原数组,非纯函数方法反之,下面说的API都是一些常见的API((其他实现请在网站下面评论,或者大家自己手写一遍))
/*
纯函数API :
concat
filter
map
reduce
slice
非纯函数API
splice
shift(unshift同理)
reverse
*/
纯函数API
Array.prototype.concat
mdn定义 : concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
语法
var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])
let arr = ['name' , {a:'zhoujing'}]
let b = [].concat(arr)
//b = ['name' , {a:'zhoujing'}]
arr[1].a = 'lvshui'
//b =['name',{a:'lvshui'}]
需要注意的点
- concat方法不会改变this或任何作为参数提供的数组,而是返回一个浅拷贝.也就是说,如果数组里有引用对象的话,拷贝过来的是引用地址
实现一个简易concat
//实现一个简易concat
Array.prototype._concat = function(...args){
let context = this , result = [];
if(!args.length){
return context
}
//如果没有参数,直接返回this
args.forEach( item => {
if(Object.prototype.toString.call(item) !== '[object Array]'){
result.push(item)
//判断参数里面有没有数组
}else{
item.forEach( it => result.push(it))
}
})
return result
}
console.log( []._concat(1,2,3,3,45))
console.log( []._concat(1,2,3,{name:'dd'},45))
console.log( []._concat([1,[2]],3,3,45))
console.log( []._concat() )
// [ 1, 2, 3, 3, 45 ]
// [ 1, 2, 3, { name: 'dd' }, 45 ]
// [ 1, [ 2 ], 3, 3, 45 ]
// []
Array.prototype.filter
mdn定义 : filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
语法
var new_array = arr.filter(callback(element[, index[, array]])[, thisArg])
需要注意的点
- filter方法不会改变原数组,它返回过滤后的新数组。
- 这个过程是一次性的,后面数组改变不会影响filter的值
实现一个简易版filter函数
//实现一个简易filter
Array.prototype._filter = function(cb,thisArg){
let context = this
let cbThis = thisArg ? thisArg : null
let result = []
//this默认指向this,提供了thisArg的情况下指向thisArgs
context.forEach( (item,index,arr) => {
if(cb.call(cbThis,item,index,arr)){
result.push(item)
}
})
return result
}
console.log( [1,2,3,43]._filter( item => item&1 == 1 ) )
console.log( []._filter(item => item&1 == 1 , [1,2,3,43]) )
//[ 1, 3, 43 ]
//[]
Array.prototype.map
mdn定义 : map() 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。
语法
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
需要注意的点
- map方法不会改变原数组,它返回新数组。
- callback 函数会被自动传入三个参数:数组元素,元素索引,原数组本身。
- map函数的第二个参数是可选项,作为callback的this指向
//实现一个简易map
Array.prototype._map = function(cb,thisArg){
let context = this
let cbThis = thisArg ? thisArg : null
let result = []
//this默认指向this,提供了thisArg的情况下指向thisArgs
context.forEach( (item,index,arr) => {
result.push( cb.call(cbThis,item,index,arr) )
})
return result
}
console.log( [1,2,3]._map(Math.sqrt) )
console.log( [1,2,3]._map((index,item)=>{ return index * 2 + item}) )
// [ 1, 1.4142135623730951, 1.7320508075688772 ]
// [ 2, 5, 8 ]
Array.prototype.reduce
mdn定义 : reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
语法
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
需要注意的点
- reduce方法不会改变原数组,它返回一个值。
- 提供初始值initialValue会更加安全(建议)
//实现一个简易reduce
Array.prototype._reduce = function(reducer,initialValue){
let context = this , startIndex = 1
debugger
//this默认指向this,提供了thisArg的情况下指向thisArgs
if(initialValue !== undefined){
startIndex = 0
}else{
initialValue = context[0]
}
for(let i = startIndex ; i < context.length ; i ++){
initialValue = reducer(initialValue,context[i],i,context)
}
return initialValue
}
console.log([1,2,3,34]._reduce((a,b) => a+b , 12))
console.log([1,2,3,34]._reduce((a,b) => a.concat(b) , []))
// 52
// [ 1, 2, 3, 34 ]
Array.prototype.slice
mdn定义 : slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。
语法
arr.slice([begin[, end]])
需要注意的点
- slice方法是对数组项的浅拷贝
- slice方法不会对原始数组进行修改
//实现一个简易slice
Array.prototype._slice = function(...args){
let len = this.length , result = []
let startIndex = args[0] === undefined ? 0 : args[0]
let endIndex = args[1] === undefined ? len : args[1] >= len?len:args[1]
for(let i = startIndex ; i < endIndex ; i ++ ){
result.push(this[i])
}
return result
}
console.log( [1,2,3,34,3,3,3,33,3]._slice() )
//[1, 2, 3, 34, 3,3, 3, 33, 3]
非纯函数API
Array.prototype.splice
mdn定义 :splice()方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
语法
array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
需要注意的点
- 指定修改的开始位置(从0计数)。如果超出了数组的长度,则从数组末尾开始添加内容;如果是负值,则表示从数组末位开始的第几位(从-1计数,这意味着-n是倒数第n个元素并且等价于array.length-n);如果负数的绝对值大于数组的长度,则表示开始位置为第0位。
- 如果 deleteCount 大于 start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。 如果 deleteCount 被省略了,或者它的值大于等于array.length - start(也就是说,如果它大于或者等于start之后的所有元素的数量),那么start之后数组的所有元素都会被删除。 如果 deleteCount 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素
//实现一个简易splice
Array.prototype._splice = function(startIndex,count,...items){
debugger
let context = this , len = context.length;
let temp = this.slice()
startIndex = startIndex < 0 ? Math.abs(startIndex>=len)?0:len + startIndex : startIndex
//这里是判断startIndex负值相关情况
//这里是判断count值得情况
count = count <=0 ? 0 : count//count可以是负值
if( count >= len - startIndex ){
for(let i = 0 ; i < len - startIndex ; i ++){
context.pop()
}
items.forEach( item => {
context.push(item)
})
}else{//正常情况下得
context.length = len - count + items.length//数组原地操作
for(let j = context.length - 1 ; j >= startIndex + count ; j--){
context[j] = context[ j + count - items.length ]
}
for(let i = 0 ; i < items.length ; i ++){
context[startIndex + i] = items[i]
}
}
console.log(this)
return count === undefined ? temp.slice(startIndex) : temp.slice(startIndex,startIndex + count)
}
console.log( [1,2,3,34]._splice(1,2,3,4,45) )
// [ 1, 3, 4, 45, 34 ]
// [ 2, 3 ]
Array.prototype.shift
mdn定义 : shift() 方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。
语法
arr.shift()
需要注意的点
- shift方法并不局限于数组,这个方法能够通过 call 或 apply 方法作用于类似数组的对象上.前提是对象具有length属性
//实现一个简易shift
Array.prototype._shift = function(){
if(!this.length) return undefined;
let context = this.slice()
for(let i = 0 ; i < this.length ; i ++){
this[i] = this[i+1]
}
this.length--
console.log(this)
return context[0]
}
console.log( []._shift() )
// undefined
// [ 2, undefined, 3, 4, 54, 56, 76 ]
Array.prototype.reverse
mdn定义 : 方法将数组中元素的位置颠倒,并返回该数组。数组的第一个元素会变成最后一个,数组的最后一个元素变成第一个。该方法会改变原数组。
语法
arr.reverse()
需要注意的点
- 方法颠倒数组中元素的位置,改变了数组,并返回该数组的引用。
- 也可应用于类数组对象中(建议查看MDN原文档)
//实现一个简易reverse
Array.prototype._reverse = function(){
if(!this.length || this.length === 1) return this;
let len = this.length , middle = parseInt(len / 2)
for(let i = 0 ; i < middle ; i++){
index = this[i]
this[i] = this[len-i-1]
this[len-i-1] = index
}
return this
}
console.log( [1,2,3,4,54,56,76]._reverse() )
console.log( [0,1,2,3,4,54,56,76]._reverse() )
// [76, 56, 54, 4,3, 2, 1]
// [76, 56, 54, 4,3, 2, 1, 0]