美文网首页
数组操作

数组操作

作者: lyp82nkl | 来源:发表于2019-06-17 01:15 被阅读0次

数组的七个 API 的实现

join()

将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。

var array = ['a','b','c']
array.join('-') // 结果是 'a-b-c'

画一下内存图:


jzdg9gaxm4hh.png
  • array.join 实际上是 Array.prototype.join 对应的函数(array.join === Array.prototype.join === ADDR401)
  • array.join('-') 等价与 array.join.call(array, '-')
  • join 函数通过 this 和 arguments[0] 可以得到 array 和 '-' 两个值
    所以我们可以大胆猜测 array.join 的源代码大概是这样的
  //只接受一个参数; char 是 '-'  的意思
    Array.prototype.join = function(char){ 
        // 用 this 来接收数组
        // 首先 取第一个值 this[0] ,如果没有就是空字符
        let result = this[0] || ''
        let length = this.length
        // 遍历 this 
        for (let i =1; i < length; i++){
        //再从 i=1 (第二个值)开始取
        //遍历 this ,让 result 每次都加上 '-' 再加上 第 i 个值 
            result +=char + this[i]
        }
        return result
    }

this 就是 array,因为你使用 array.join('-') 来调用 join 的(隐式指定this)

slice()

返回一个新的数组对象,这一对象是一个由 begin和 end(不包括end)决定的原数组的浅拷贝。原始数组不会被改变。

array.slice(beginIndex, endIndex)

显而易猜,源码大概大概大概是这样的

    //Array 原型 有个slice 属相 ,接受两个参数(开始,结束)
    Array.prototype.slice = function(begin, end){
        // 声明一个空数组
    let result = []
    //如果 begin 不存在,让begin是 0
    begin = begin || 0
    // 如果 end 不存在,让 end 是 数组的长度
    end = end || this.length
    // 遍历数组
    // i 从 0 到 end , 每一个都 push 到  result数组 里面
    for(let i = begin; i< end; i++){
        result.push(this[i])
    }
    return result
}

于是很多前端用 slice 来将伪数组,转化成数组

array = Array.prototye.slice.call(arrayLike)
或者
array = [].slice.call(arrayLike)

ES 6 看不下去这种蹩脚的转化方法,出了一个新的 API

array = Array.from(arrayLike)

专门用来将伪数组转化成真数组。
注意:伪数组与真数组的区别就是:伪数组的原型链中没有 Array.prototype,而真数组的原型链中有 Array.prototype。因此伪数组没有 pop、join 等属性。

sort()

方法用原地算法对数组的元素进行排序,并返回数组。排序算法现在是稳定的。默认排序顺序是根据字符串Unicode码点。

  • 听说大部分的语言内置的 sort 方法都是快速排序算法。我们就简化成选择排序吧
 //给数组排序
    // sort 接受一个函数 fn 
    Array.prototype.sort = function(fn){
        //fn 默认就是一个 a-b  这样的函数
        fn = fn || ((a,b)=> a-b)
        // 两个数 ,谁小就将谁放在第一位
        // 所以两个数只有排一轮,三个数排两轮  ;this.length - 1
        let roundCount = this.length - 1 // 比较的轮数
        for (let i = 0; i< roundCount; i++){
            // 假定 第一轮的第一个就是最小的
            let minIndex = this[i]
            //遍历
            for(let k = i+1; k < this.length; K++){
                // 调用这个函数,这个函数用第一个参数 减去 第二个参数(a - b)
                // this 的 看k 项 减去 this 的 i 项 ,若值 <0 ,第 k 项比第 i 项 小
                if(fn.call(null,this[k],this[i]) < 0){
                    // 小的要放在前面,所以讲 第 k 项的值与 第 i  项的值互换
                    [this[i],this[k] = [this[k],this[i]]]
                }
            }
        }

    }
es6 语法 ,a 与b 的值互换
a = 'a'
//"a"
b ='b'
//"b"
[a,b]=[b,a]
//(2) ["b", "a"]
a
//"b"
b
//"a"
  • fn.call(null, this[k], this[i]) 决定了第 k 项和第 i 项的前后(大小)关系。
  • fn 为 (a,b) => a-b 表示啥?fn 为 (a,b) => b-a 又表示啥?
    不重要,因为如果前者不符合你的需求,那么后者一定符合你的需求,你只需要试两边就知道用哪一个了。
forEach()

对数组的每个元素执行一次提供的函数。

forEach源代码:

    Array.prototype.forEach = function(fn){
        //遍历 this
        for (let i=0; i < this.length;i++){
             // 如果 i 是 this 的 key
            if( i in this){
                fn.call(undefined, this[i], i ,this)
            }
        }
    }
a = [1,2,3]
(3) [1, 2, 3]
a.forEach ( (item)=>{
    console.log(item)
})
VM132:2 1
VM132:2 2
VM132:2 3

a.forEach((item,index,array)=>{
    console.log(item ,index,array )
 // fn.call(undefined, this[i], i ,this)
})
1 0 (3) [1, 2, 3]
 2 1 (3) [1, 2, 3]
 3 2 (3) [1, 2, 3]

forEach 把给我的函数在遍历的时候 call 一下
//fn 是  (item)=>{console.log(item) 这个函数
// a 是 this       
//a[i]] 是 this[i]  

//用item 来命名第一个参数 this[i]                               元素
//用 index 来命名 i                                            下标
//array 来表示 this ,因为已经知道了this 是a 这个数组            整个数组

forEach 和 for 的区别主要有两个:

  1. forEach 没法 break
    break: 此语句导致程序终止包含它的循环,并进行程序的下一阶段(整个循环后面的语句),即,不是跳到下一个循环周期而是退出循环。
  2. forEach 用到了函数,所以每次迭代都会有一个新的函数作用域;而 for 循环只有一个作用域(著名前端面试题就是考察了这个)
map():映射

创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。

Array.prototype.map = function(fn){
    let result = []// 空数组
    for(let i=0;i<this.length; i++){
        if(i in this) {
            result[i] = fn.call(undefined, this[i], i, this)
        }
    }
    return result //将返回的值放到数组里面
}
  • 由于 map 和 forEach 功能差不多,区别只有返回值而已,所以我推荐忘掉 forEach,只用 map 即可。
  • 想用 map 的返回值就用,不用想就放在一边。

filter():过滤

创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。就是 过滤操作。

   Array.prototype.filter = function(fn){
        let result = []
        let temp
            for(let i=0;i<this.length;i++){
                if(i in this){
                    if(temp = fn.call(undefined,this[i],i,this)){
                        // 判读temp = fn.call()的值是否为真值 
                        //值为真 就放入数组里面
                        result.push(temp)
                        // 有选择的将值加入数组(满足条件)
                    }
                }
            }
        return result
    }


<!-- 6个假值
    false  0  ''  NAN    undefimed  null
-->


a = [1,2,3,4,5,6]
(6) [1, 2, 3, 4, 5, 6]
a.filter((value)=>{  
return value % 2 ===0
})
(3) [2, 4, 6]
  • fn.call() 返回真值就 push 到返回值,没返回真值就不 push。
reduce :求和

对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。

 Array.prototype.reduce = function(fn,init){
        let result = init//初始值
        // 遍历每一个元素;fn.call()
        // 除了 this[i],i,this 这三个参数,还要传一个每一次调用之后(上一次)的结果
        //reduce :每一次把上次的结果和当前的数字进行操作;fn进行操作
        for(let i=0;i<this.length;i++){
            if(i in this){
                result  = fn.call(undefined,result,this[i],i,this)
            }
        }
        return result
    }
    
    
    
    
    a= [1,2,3,4,5]
(5) [1, 2, 3, 4, 5]
a.reduce((result,item,index,arrray)=>{
    return result + item
},0) 
15
map、filter 和 reduce 的区别:
  • map 是等量的一对一的关系
  • filter 是从多到少的过程 (过滤)
  • reduce 进行一个累加
map、filter 和 reduce 的联系:

map 可以用 reduce 表示

 array2 = array.map( (v) => v+1 )
 可以写成 
 array2 = array.reduce( (result, v)=> {
     result.push(v + 1)//push 当前值加 1
     return result //返回 result作为下一次的result
 }, [ ] )//result 最开始是空数组

filter 可以用 reduce 表示

 array2 = array.filter( (v) => v % 2 === 0 )
 可以写成
 array2 = array.reduce( (result, v)=> {
     if(v % 2 === 0){ result.push(v) }
     return result
 }, [])

相关文章

  • 数组

    数组定义: 元素类型 数组操作 Range 数组的批量操作 遍历

  • 迟到的Swift入门 - 数组操作

    Swift数组操作 1. 数组的日常操作 1.0 声明数组 初始化空数组 初始化默认值的数组 2. 数组基本操作 ...

  • 2. Numpy使用

    numpy的基本操作 生成数组 数组的基本操作 数组的运算 数组间的运算

  • 数组和对象的操作

    数组操作方法 数组中splice的操作(改变的是原数组,返回结果是分割的数组) 数组中slice的操作(不改变原数...

  • Matrix01-03:ndarray数组的操作

    ndarray数组的操作 数组数据转换数组形状变换数组数据选择与操作数组计算处理数组算术运算 一、数组数据转换 注...

  • js基础之数组方法

    数组简单操作 数组合并 数组排序

  • 基本dom操作,数组操作

    dom操作 数组操作

  • java笔记5

    数组的定义 数组的内存分配及特点 数组操作常见问题 数据常见操作 数组中的数组 @Test public void...

  • 数组类常用操作方法

    一、数组 二、不可变数组(NSArray) 三、不可变数组的操作 四、可变数组(NSMutableArray)的操作

  • JavaScript 数组方法整理大全

    一、常用的数组方法★ 直接操作影响原数组的方法: ★ 直接操作不影响原数组的方法: ★ 直接操作有可能影响到原数组...

网友评论

      本文标题:数组操作

      本文链接:https://www.haomeiwen.com/subject/pumnfctx.html