180326 数组

概述

  • 数组是值的有序集合,其中值称作‘元素’,对应位置称作‘索引’
  • 数组继承Array.prototype中的属性
  • 数组是对象的特殊形式,数组索引实际上和碰巧是整数的属性名差不多

创建数组

  • 数组直接量
var arr = [1,2,'a'];

var arr1 = [[1,{x:1,y:2}],[2,{x:3,y:4}]];
// 可以包含对象直接量或其他数组直接量。

var arr2 = [1, , ,2, ,'a', ,0];
//稀疏数组 arr2[2] = undefined  arr.length = 8
//如果省略数组直接量中的某个值,省略的元素将被赋予undefined值

var arr3 = [ , , ];
//两个元素undefined 数组直接量结尾的逗号可选择
  • 调用构造函数
=1= 调用时没有参数
var a = new Array();
//相当于var a = [];

=2= 调用时有一个数值参数(一个数,整数),它指定数组长度
var a = new Array(10);

=3= 显示指定两个以上的数组元素或非数值元素
var a = new Array('test');
var a = new Array(5,4,3,2,1,'testing');
  • 比较
var a = [8];
var b = new Array(8);
console.log(a);
console.log(b);
console.log(a.length);
console.log(b.length);

这里写图片描述


  • 删除
=1= delete

var a = [1,'a',3, ,'b',6];
console.log(a,a.length);
delete a[1];
// 删除盒子里的东西,盒子还在
console.log(1 in a);
console.log(a,a.length);
// 从数组中删除一个元素,它就变成稀疏数组
-----------------------------------------------
=2= 新的期望数组长度
var a = [1,2,3,4,5,6,7];
console.log(a,a.length);
a.length = 4;
console.log(a,a.length);

这里写图片描述

这里写图片描述


判断数组的方法:

  1. instanceof
  2. object.prototype.toString (跨域常用)
  3. constructor

数组读写

var a = [1,2];
console.log(a[9]);
//溢出读没意义

var b = ['a','b'];
b[10] = 9;
console.log(b);
//可以溢出写

这里写图片描述

  • 数组是特殊的对象,索引都是属性名。 数组[索引] -> 对象[属性]
  • 但只有0~2e32-2之间的整数属性名才是索引。
  • 所有的数组都是对象,可以为其创建任意名字的属性。
  • 但如果使用的属性是数组的索引,数组的特殊行为就是将根据需要更新length属性值。
  • 可以使用负数或非整数来索引数组。这时候数值转化为字符串,字符串作为属性名使用,此时当做对象的属性看待。
  • 特别的,使用 非负整数的字符串,则会当做数组索引。
function roc(a,prop){
    console.log(a[prop]);
    console.log(a);
    console.log(a.length);
}
var a = [];
a[1] = 1;
roc(a,1.000);
a[-1.23] = true;
roc(a,-1.23);
a['1000'] = 0;
roc(a,'1000');

稀疏数组

  • 稀疏数组就是包含从0开始的不连续索引的数组。
a = new Array(5);  // 数组没有元素,但是数组长度是5
a = [];   // 创建一个空数组,数组长度是0
a[1000] = 0; // 赋值添加一个元素,但是设置长度为1001
  • 当省略数组直接量中的值时(使用连续逗号),这时多得到的数组也是稀疏数组,省略掉的值是不存在的。
  • 通过调用构造函数创建数组,创建的是稀疏数组,数组元素根本不存在。
var a1 = [, , , ];
var a2 = new Array(3);
var a3 = [undefined, , , ];
console.log(a1);
console.log(a2);
console.log(a3);
console.log(0 in a1);
console.log(0 in a2);
console.log(0 in a3);

这里写图片描述


数组长度

数组的特殊行为

  • 当索引i大于或等于现有数组的c长度时,length属性的值将设置为i + 1;
  • 设置length属性为一个小于当前长度的非负整数n时,当前数组中索引值大于或等于n的元素将从中删除。

添加和删除数组元素

  • 为新索引赋值
var a = [];
a[2] = 9

push()方法(改变原数组)

从尾部加入元素

  • 作用:尾部插入元素,增加数组长度
  • 参数:推入的值
  • 返回值:数组长度

    组合使用push()pop()可以实现先进后出的栈

var arr = [1];
console.log(arr,arr.push(2,3,4));
// [1,2,3,4] 4

//模拟源码实现push功能
var arr = [1, 2];
Array.prototype.myPush = function() {
    for (var i = 0; i < arguments.length; i++) {
        this[this.length] = arguments[i];
    }
    return this.length;
}
arr.myPush('a', 'b', 'c');
arr.myPush('d', 'e');

pop()方法(改变原数组)

弹出最后一个元素的值

  • 作用:删除数组最后一个元素,减小数组长度
  • 返回值:弹出的值
var arr = [1,2,3,4];
console.log(arr,arr.pop());
// [1,2,3] 4

//模拟源码实现pop功能
Array.prototype.myPop = function() {
    var val = this[this.length - 1];
    this.length -= 1;
    return val;
}
arr.myPop();
var arr = [1, 2, 3, 4];
var a = arr.pop();
console.log(a, arr, arr.length);
// 使用pop方法,数组长度减少

这里写图片描述


unshift()方法 (改变原数组)

头部插入一个元素

  • 参数:插入元素
  • 返回值:数组长度

    与splice()一样,参数是一次性插入的,插入顺序和在参数列表中的参数一致。

var arr = [1, 2, 3];
arr.unshift('a', 'b', 'c');

var arr = [1, 2, 3];
Array.prototype.myUnshift = function() {
   var newArr = [];
   for (var i = 0; i < arguments.length + this.length; i++) {
       newArr[i] = i < 2 ? arguments[i] : this[i - arguments.length];
       //新数组 = 新增的类数组 + 原数组
       //new[i = 0] = arguments[0]
       //new[i = 1] = arguments[1]
       //new[i = 2] = arr[i - arguments.length] 
       //new[i = 3] = arr[i - arguments.length]
       //i < 2 + 3 
   }
   for (var i = 0; i = newArr.length; i++) {
       this[i] = newArr[i];
   }
   return this.length;
}
// arr.myUnshift('a', 'b');

这里写图片描述


shift()方法 (改变原数组)

弹出头部第一个元素

  • 返回值:弹出元素
var arr = ['a','b','c'];
console.log(arr);
console.log(arr,arr.shift());
//shift同样改变数组长度

这里写图片描述

这里写图片描述


splice()方法(改变原数组)

指定位置插入删除

  • 作用:指定位置 插入、删除元素
  • 参数:
    • 第一个参数:插入/删除起始位置
    • 第二个参数:指定从起始位置删除元素的个数(0不删 | 不填全删)
    • 第三个参数:新插入的元素 本身(若插入元素是数组,区别于concat(),会插入数组本身)
  • 返回值:被删除的元素数组
var a = [1,2,3,4,5,6,7,8];
a.splice(4);//第二个参数没填,起始位置后全删
a.splice(1,2);//第三个参数没填,仅删除元素
a.splice(1,1);//在原数组上改变

这里写图片描述

var a = [1,2,3,4,5];
a.splice(2,0,'a','b');//不删除
a.splice(2,2,[1,2],3);//插入数组本身

这里写图片描述


数组遍历

  • for
var arr = [1, 2, 3, 4, 5, 6, 7, 8];
var keys = Object.keys(arr);
var values = [];
for (var i = 0 , len = keys.length; i < len; i++) {
//优化,数组的长度只查询一次
    var key = keys[i];
    values[i] = arr[key];
}
console.log(values);
  • 探究

    • Object.keys()方法 (传入对象、数组 返回属性名、索引)

      Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for…in 循环遍历该对象时返回的顺序一致 (两者的主要区别是 一个 for-in 循环还会枚举其原型链上的属性)。
      这里写图片描述

var arr = [1, , 3, 4, , 6, 7, 'a'];
var roc = Object.keys(arr); //返回索引,是一个数组
console.log(roc);
var newArr = [];
for (var i = 0, len = roc.length; i < len; i++) {
    // 此处遍历len = 6 , i = 0 ~ 5
    newArr[i] = arr[i];

    // nA[0]=arr[0]=1 
    // nA[1]=arr[1]=(empty->undefined) 
    // nA[2]=arr[2]=3
    // why不直接将原数组的索引对应值直接赋值新数组
}
console.log(newArr);
console.log(1 in newArr);
newArr[2] = 100;  // 猜测正确,空赋值给新数组,变成undefined,但此时该索引上存在元素
console.log(newArr);
console.log(arr);
console.log(1 in arr); // 原本就是空数组

这里写图片描述

var arr = [1, , 3, 4, , 6, 7, 'a'];
var roc = Object.keys(arr); 
console.log(roc);
var newArr = [];
for (var i = 0, len = roc.length; i < len; i++) {
    var rocs = roc[i];
    newArr[i] = arr[rocs];
}
console.log(newArr);
console.log(1 in newArr);

newArr[2] = 100;
console.log(newArr);
console.log(arr);
console.log(1 in arr);

// === 过滤稀疏数组,遍历后得到 ===

这里写图片描述

  • forEach

    • 从头至尾遍历数组,为每个数组调用指定函数
    • 可以传三个参数:数组元素,索引,数组本身
    • 如果只关心数组元素的值,可以只写一个参数
var data = [1, 2, 3, 4, 5];
var sum = 0;
data.forEach(function(value) {
    sum += value;//将每个值累加到sum上
});
console.log(sum);

data.forEach(function(v, i, a) {
    a[i] = v + 1; //每个元素的值自加1
});
console.log(data);
var a = [1, 2, 3, 4, 5, 6];


a.forEach(function(ele, index,arr) {
     console.log(ele, index,arr);//输出每个元素及对应的索引
})

//模拟源码
Array.prototype.myForEach = function(func) {
    for (var i = 0; i < this.length; i++) {
        func(this[i], i);
    }
}
arr.myForEach(function(ele, index) {
    console.log(ele, index);
})

这里写图片描述
这里写图片描述

  • filter()方法(条件遍历)

    • 根据逻辑条件返回调用数组子集,对数组元素进行筛选
    • 会跳过稀疏数组中缺少的元素。它的的返回数组总是稠密的。
var a = [5, 4, 3, 2, 1];
b = a.filter(function(ele) {
    return ele > 3 //筛选元素大于3的元素
});
console.log(b);
c = a.filter(function(ele, index) {
    return index % 2 == 0 //筛选索引为偶数的元素
})
console.log(c);


var arr = [1, , 3, 4, , 6];
var newArr = arr.filter(function(ele, index) {
    return true;//压缩稀疏数组空缺,返回稠密数组
    // return false;
})

var arr1 = arr.filter(function(ele, index) {
    if (ele > 3) {
        return true
    } else {
        return false
    }
})

这里写图片描述
这里写图片描述

这里写图片描述

这里写图片描述


数组排序

  • sort()方法(值转换成->ASCII码 | 传参)
  • 参数是一个比较函数

  • 有关规则:大的、返回值1、置后 小的、返回值-1、置前

var arr = [100, 2, 0, 106, 7, 8];
arr.sort(); //(其实,在使用sort()进行排序的时候会调用toString()函数将其值转换成字符串在进行比较,是按ASCII进行比较的)
console.log(arr);
arr.sort(function(first, last) {
    return first - last; //正序
    // return last - first; //倒序
    // return Math.random() - 0.5; //乱序
    // return -1;//ASC码正序
    // return 1; //ASC码倒序
});
console.log(arr);

var arr = [{name: 'tyx',search: 24005}, 
           {name: 'hx',search: 35637},
           {name: 'jj',search: 19800},
           {name: 'po',search: 59043}];
arr.sort(function(a, b) {
    return a.search - b.search;
})

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

var a = ['ant', 'Bug', 'cat', 'Dog'];
a.sort();
console.log(a);

a.sort(function(f, l) {
    var a = f.toLocaleLowerCase();
    var b = l.toLocaleLowerCase();
    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
})
console.log(a);

这里写图片描述

这里写图片描述

  • reverse()方法(逆序排序)
var arr = [1, 2, 3, 4, 5, 6];
arr.reverse();//逆序排序
console.log(arr);
arr.sort(function(f, l) {
    return f - l
});
console.log(arr);
arr.sort(function(f, l) {
    return l - f
});
console.log(arr);

这里写图片描述


数组方法

改变原数组的方法:

reverse() sort()

push() pop() unshift() shift() splice()

不改变原数组的方法:

join() concat() slice() toString()

map() reduce() every() some() filter()

indexOf() forEach()



  • join()

    将数组中所有元素连接在一起返回生成字符串,可以指定字符分割生成字符串

var a = ['a','b','c'];
a.join();
a.join(" ");
a.join("");
var b = new Array(10);
b.join("-");

这里写图片描述


  • concat()

    合并数组,创建一个新数组 = 原数组 + 参数
    如果参数自身是数组,则连接数组中的元素
    concat()不会递归扁平化数组中的数组

var a = [1,2,3];
a.concat(4,5);//a[i] + 4,5
a.concat([4,5]);//连接数组元素
a.concat([4,5],[6,7]);
a.concat(4,[5,[6.7]]);//不会递归扁平化数组

这里写图片描述

  • slice()(不改变原数组)

    返回指定数组的一部分
    含有两个参数开始位置 结束位置不包含结束位置的参数
    若一个参数,表示从这个参数开始到结束
    若参数为负值,表示相对于最后一个元素的位置
    -1表示最后一个元素

var a = [1,2,3,4,5];
a.slice(0,3);
a.slice(3);
a.slice(1,-1);
a.slice(-3,-2);//相当于(3,4)

这里写图片描述


toString()和toLocaleString()

数组 -> 字符串

array.toString();  [return string]
  • 作用:将数组的每个元素 转化为字符串
  • 返回值:字符串

    • 相当于不使用任何参数调用 join()方法
    • 本地化版本,使用本地化分隔符连接
var a = [1, 2, 3, 4, 5, 'a', '8'];
console.log(a.toString());
console.log(a.join());

这里写图片描述


map()

对数组每个元素加工

array.map(function(ele){
    return newArray;
})
  • 作用:将每个元素传递给指定函数,经过运算或加工
  • 参数:callback(currentValue) 操作函数
  • 返回值:一个新数组

    • 如果是稀疏数组,返回的也是对应的稀疏数组(相同长度和缺失元素)
var a = [1,2,3];
a.map(function(x){return x*x;})  // 1 4 9
["1","2","3"].map(parseInt);   //1,NaN,NaN

通常使用parseInt时,只需要传递一个参数。但实际上,parseInt可以有两个参数,第二个参数是进制数,可以通过语句“alert(parseInt.length) === 2”来验证。

  map()方法在调用callback函数时,会给它传递三个参数:当前正在遍历的元素、元素索引、原数组本身。第三个参数parseInt会忽视,但第二个参数不会,也就是说,parseInt把传过来的索引值当成进制数来使用,而parseInt的第二个参数的范围为2~36(不包含2但包含36),如果省略该参数或者其值为0,则数字将以10为基数来解析;如果小于2或者大于36,parseInt()将返回NaN,所以最终返回了[1,NaN,NaN]。

  实际上,这个小例子可以分解成这样理解:

parseInt("1",0);  //基数为0,以十进制来解析,返回1
parseInt("2",1)  //基数为1,小于2,返回NaN
parseInt("3",2)  //基数为2,小于2,返回NaN

every()和 some()

判断数组元素是否全部或部分满足一定条件

array.every(function(currentValue[元素值必须],index[可选],arr[可选]), thisValue)
array.every(function(ele){
    return boolean;
});
  • 作用:对数组元素逻辑判定,是否满足一定条件
  • 参数:callback回调函数(数组元素值)
  • 返回值:布尔值
    • every()针对所有元素判定为true,函数才返回true
    • some()至少含有一个元素判定为true,函数返回true
    • 根据惯例,在空数组上调用,every()返回true,some()返回false
var a = [1, 2, 3, 4, 5];

a.every(function(ele) {
    return ele < 10  // true
})
a.every(function(ele) {
    return ele % 2 == 0 // false
})
a.some(function(ele) {
    return ele % 2 == 0; //是否存在一个元素被2整除
})    // true
a.some(isNaN); // 是否存在一个元素是非数字  false

reduce()和 reduceRight()

数组前后项做运算 返回累计值

array.reduce(function(ele){
    return result;
});
  • 作用:让数组 前一项后一项 进行 某种运算,并 累计最终值
  • 两个参数 :第一个是操作函数,用某种方法把两个值化简成一个值并返回。第二个是参数是传给函数一个初始值(可选)
    • 当不传第二个参数时,将使用数组的第一个元素作为初始值
  • 返回值:操作函数执行后的累计值(一个运算结果)

    • 关于操作函数的参数有两个:前一项和后一项
var a = [1, 2, 3, 4, 5];

a.reduce(function(x, y) {
    return x + y;  
    //reduce两个参数:操作函数(两个参数:前一项;后一项);初始值
}, 0)   //15

a.reduce(function(x, y) {
    return x * y  //数组求积
}, 1)    // 120

a.reduce(function(x, y) {
    return (x > y) ? x : y; //求最大值
})
       //5

indexOf()和 lastIndexOf()

匹配 给定值与数组元素

Array.indexOf (search, location)  [return index]
String.indexOf (search, location)
  • 作用:正向或逆向 根据给出值 匹配 数组 元素
  • 两个参数搜索值搜索起始位置 (默认从头开始 [0],负数表示相对于数组末位的偏移量)
  • 返回值第一个匹配元素的索引,或整个数组不匹配返回-1
var a = [0, 1, 2, 1, 0];
a.indexOf(1);   //  正向从头搜索值1  返回值 1 表示索引
a.lastIndexOf(1); //  逆向从头搜索值1  返回值3
a.indexOf(3);//  返回值-1

'btn mbtn'.indexOf('m');
  • 搜索指定的值,并返回包含所有匹配的数组索引的一个数组
function findAll(matchingArr, search) { // 匹配数组,搜索值
    var resultArr = [], //创建结果数组
        len = matchingArr.length, //记录数组长度
        position = 0; //记录检索位置
    while (position < len) { // 索引对应,开始循环遍历
        position = matchingArr.indexOf(search, position);
        //第一次匹配索引更新到position
        if (position === -1) break;
        resultArr.push(position); //将返回值压入结果数组
        position = position + 1; //让索引从下一位开始,此时pos并不是pos++,而是根据上面的方法返回值索引,下一次从该值继续检索
    }
    return resultArr;
}

var arr = ['a', 2, 'a', 'aa', 4, 'g', 7, 4, 5, 'a', 6, 9, 'a', 6, 4, 3, 'a', '7', 'a'];
findAll(arr, 'a');

这里写图片描述


  • 比较各个函数

    这里写图片描述
    这里写图片描述
    这里写图片描述


判断数组类型

  • Array.isArray();
console.log(Array.isArray([]));
console.log(Array.isArray({}));

这里写图片描述


数组特性

  • 当有新的元素添加到列表,会自动更新length
  • 设置length为一个较小值会截断数组
  • 从Array.prototype中继承有用方法
  • 类属性是‘Array’

类数组

  • 类数组[] 当一个对象中的属性名是数字(类似数组索引),且有属性length时,作类数组。 {2:,3:,length:2} = []
var obj = {
    2: 'a',
    3: 'b',
    push: Array.prototype.push,
    splice: Array.prototype.splice
};
console.log(obj);

这里写图片描述

var obj = {
    2: 'a',
    3: 'b',
    length: 2,
    push: Array.prototype.push,
    splice: Array.prototype.splice
};
console.log(obj);

这里写图片描述

  • 可以利用属性名[索引]模拟数组的特性
  • 可以动态的增长length属性
  • 如果强行让类数组调用push方法,则会根据length属性值的位置进行属性的扩充
var obj = {
    2: 'a',
    3: 'b',
    length: 2,
    push: Array.prototype.push,
    splice: Array.prototype.splice
};

obj.push('c'); // obj[2] = 'a' <- 'c'  length++ 
console.log(obj);
obj.push('d'); // obj[3] = 'b' <- 'd'  length++
console.log(obj);

//涉及预编译、push方法 实现源码原理

var arr = [1, 2];
Array.prototype.myPush = function() {
   for (var i = 0; i < arguments.length; i++) {
       this[this.length] = arguments[i];
   }
   return this.length;
}
arr.myPush('a', 'b', 'c');
arr.myPush('d', 'e');

这里写图片描述

  • 类数组对象没有继承自Array.prototype,而是Object.prototype那就不能在它们上面直接调用数组方法。但是可以间接的使用Function.call方法调用:
function roc(x){
    console.log(x);
}
var a = {'0':'a','1':'b','2':'c',length:3};
roc(a);
var b = Array.prototype.join.call(a,'+');
roc(b);
var c = Array.prototype.splice.call(a,1,0,'d');
roc(a);
roc(c);
var d = Array.prototype.map.call(a,function(x){
    return x.toUpperCase();
})
roc(d);

这里写图片描述


作为数组的字符串

  • ES5中,字符串的行为类似只读数组。
  • 可以用charAt()方法、[ ] 来访问单个字符
var s = test;
s.charAt(0);
s[1];
  • 字符串的行为类似于数组,通用的数组方法可以应用到字符串
  • 注意,字符串是不可变值,当作数组时它们是只读的。
  • push,sort,reverse,splice修改字符串无效,导致错误,却没有提示
s = 'JavaScript';
Array.prototype.join.call(s,' ');
Array.prototype.filter.call(s,function(x){
    return x.match(/[^aeiou]/); //只匹配非元音字母
}).join(' ');

这里写图片描述


数组去重

var arr = [10, 8, 9, 2, 8, 9, 10, 1, 2, 1, 2, 3, 9, 9, 10, 3, 5, 5];
Array.prototype.unique = function() {
    var memory = {};
    var newArr = [];
    for (var i = 0; i < this.length; i++) {
        if (!memory[this[i]]) {
            newArr.push(this[i]);
            memory[this[i]] = true;
        }
    }
    return newArr;
}

var newArr = arr.unique();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值