JavaScript数组对象

数组对象是使用单独的变量名来存储一系列的值。

创建一个数组

  • 常规方法
var myCarr=new Array();
myCarr[0] = "cat";
myCarr[1] = "dog";
myCarr[3] = "turkey";
  • 简洁方式
var myPets=new Array("cat", "dog", "turkey");  
var myPets = new Array(20);  //创建一个长度为20的数组
  • 字面

    var myPets = ["cat", "dog", "turkey"]
    

访问数组

  • 通过指定数组名以及索引号码,可以访问某个特定的元素。

    var pet = myPets[0] //获取数组的第一个元素值
    myPets[1] ="monkey" //给数组的第二个元素重新赋值
    

数组属性

  • constructor 返回创建数组对象的原型函数
  • length 设置或返回数组元素的个数
  • prototype 允许你向数组对象添加属性或方法

Array对象的属性

  • 数组合并/向数组中添加元素

    • concat() 连接两个或更多数组,并返回结果。

      var array = [1, 2, 3];
      var arr1 = ["a","b", "c"];
      array.concat(arr1)  // [1, 2, 3,"a","b", "c"]
      
    • push() 向数组末尾添加一个或更多元素,并返回新的长度

      var array = [1,2,3];
      array.push(7,8);   // 5
      
    • unshift() 向数组的开头添加一个或更多元素,并返回新的长度

      var array = [1,2,3];
      array.unshift("a", "b");  // 5
      
    • splice() 从数组中添加或删除元素

      var fruits = ["Banana", "Orange", "Apple", "Mango"];
      fruits.splice(2,0,"Lemon","Kiwi");  // 2规定从何处添加/删除,0规定应该删除多少元素,如果不设置,则删除从index开始到原数组结尾的所有元素
      console.log(fruits);   //["Banana", "Orange","Lemon","Kiwi","Apple", "Mango"]
      
  • 数组元素的删除

    • pop() 删除数组的最后一个元素并返回删除的元素

      var array = [1,2,3];
      array.pop(); // 3
      
    • shift() 删除数组的第一个元素并返回该元素的值,数组中元素自动前移

      var fruits = ["Banana", "Orange", "Apple", "Mango"];
      fruits.shift();  // Banana
      console.log(fruits); // ["Orange", "Apple","Mango"]
      
    • slice(start, end) 截取数组的一部分并返回一个新的数组(包含从start到end(不包括该元素))

      var fruits = ["Banana", "Orange", "Apple", "Mango"];
      fruits.slice(1,3);  // ["Orange", "Apple"]
      
  • copyWithin() 用于从数组指定位置拷贝元素到数组的另一个指定位置中

    var arr = ["Banana", "Orange", "Apple", "Mango",'dog','cat', 'monkey'];
    arr.copyWithin(2,0) // ["Banana", "Orange", "Banana", "Orange", "Apple", "Mango", "dog"]
    

    语法: Array.copyWithin(target, start, end)

    • target 必需。复制到指定目标索引位置
    • start 必需。 元素复制的起始位置
    • end 可选。 停止复制的索引位置(默认为array.length)
  • every() 用于检测数组所有元素是否都符合指定条件

    var ages = [32, 33, 16, 40];
    
    function checkAdult(age) {
        return age >= 18;
    }
    
    ages.every(checkAdult);   //false
    
    • 如果数组中检测到有一个元素不满足,则整个表达式返回false,且剩余的元素不会再进行检测。
    • 如果所有元素都满足条件,则返回true
    • every()不会对空数组进行检测,并且不会改变原始数组
  • fill() 用于将一个固定值替换数组的元素

    语法:array.fill(value, start, end)

    • value 必需。填充的值
    • start 可选。开始填充的位置
    • end 可选。停止填充的位置(默认为array.length)
    var fruits = ["Banana", "Orange", "Apple", "Mango"];
    fruits.fill("Runoob", 2, 4);  // ["Banana", "Orange", "Runoob", "Runoob"]
    
  • filter() 创建一个新数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。不会对空数组进行检测,不会改变原始数组。

    var ages = [32, 33, 16, 40];
    
    function checkAdult(age) {
        return age >= 18;
    }
    
    ages.filter(checkAdult);  // [32,33,40]
    
  • find() 返回符合传入测试(函数)条件的数组元素

    该方法为数组中的每个元素都调用一次函数执行:

    • 当数组中的元素满足测试条件时返回true,find()返回符合条件的元素,之后的值不会再调用执行函数
    • 如果没有符合条件的元素,则返回undefined
    • 对于空数组,函数不会执行
    • 该方法不会改变数组的原始值
    var ages = [32, 33, 16, 40];
    
    function checkAdult(age) {
        return age >= 18;
    }
    
    ages.find(checkAdult);  // 32
    
  • findIndex() 方法返回传入一个测试条件(函数)符合条件的数组第一个元素位置

    该方法为数组中的每个元素都调用一次函数执行:

    • 当数组中的元素在测试条件返回true时,该方法返回符合条件的元素的索引位置,之后的值不会再调用执行函数。
    • 如果没有符合条件的元素则返回-1
    • 对于空数组,函数不会执行
    • 该方法不会改变数组的原始值
    var ages = [32, 33, 16, 40];
    
    function checkAdult(age) {
        return age <= 18;
    }
    
    ages.findIndex(checkAdult);  // 2
    
  • forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数

  • indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。

    array.indexOf(item,start):

    • item 必须。查找的元素
    • start 可选的整数参数。规定在字符串中开始检索的位置。它的合法取值是0到stringObject.length - 1。如省略该参数,则将从字符串的首字符开始检索。
  • lastIndexOf() 返回一个指定的字符串值最后出现的位置,在一个数组中的指定位置从后向前搜索。

  • join 把数组的所有元素放入一个字符串

  • map() 通过指定函数处理数组的每个元素,并返回处理之后的数组

  • reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

  • reduceRight() 方法的功能和 reduce() 功能是一样的,不同的是reduceRight() 从数组的末尾向前将数组中的数组项做累加。

  • reverse() 反转数组的元素顺序

  • some() 检测数组中是否有元素符合指定条件

  • sort() 对数组元素进行排序

  • toString() 把数组转换为字符串,并返回结果

  • valueOf() 返回数组对象的原始值

扩展

  • Array.of方法用于将一组值,转换为数组
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1

这个方法的主要目的,是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。

Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
  • 数组实例的copyWithin()

数组实例的copyWithin方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。

Array.prototype.copyWithin(target, start = 0, end = this.length)
它接受三个参数。

target(必需):从该位置开始替换数据。如果为负值,表示倒数。
start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示倒数。
end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
这三个参数都应该是数值,如果不是,会自动转为数值。

[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]
  • Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
const target = { a: 1 };

const source1 = { b: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。

注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。

const target = { a: 1, b: 1 };

const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

注意点
(1)浅拷贝

Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);

obj1.a.b = 2;
obj2.a.b // 2

上面代码中,源对象obj1的a属性的值是一个对象,Object.assign拷贝得到的是这个对象的引用。这个对象的任何变化,都会反映到目标对象上面。

(2)同名属性的替换

对于这种嵌套的对象,一旦遇到同名属性,Object.assign的处理方法是替换,而不是添加。

const target = { a: { b: 'c', d: 'e' } }
const source = { a: { b: 'hello' } }
Object.assign(target, source)
// { a: { b: 'hello' } }

上面代码中,target对象的a属性被source对象的a属性整个替换掉了,而不会得到{ a: { b: 'hello', d: 'e' } }的结果。这通常不是开发者想要的,需要特别小心。

一些函数库提供Object.assign的定制版本(比如 Lodash 的_.defaultsDeep方法),可以得到深拷贝的合并。

(3)数组的处理

Object.assign可以用来处理数组,但是会把数组视为对象。

Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]

上面代码中,Object.assign把数组视为属性名为 0、1、2 的对象,因此源数组的 0 号属性4覆盖了目标数组的 0 号属性1。

(4)取值函数的处理

Object.assign只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制。

const source = {
  get foo() { return 1 }
};
const target = {};

Object.assign(target, source)
// { foo: 1 }

上面代码中,source对象的foo属性是一个取值函数,Object.assign不会复制这个取值函数,只会拿到值以后,将这个值复制过去。

常见用途
Object.assign方法有很多用处。

(1)为对象添加属性

class Point {
  constructor(x, y) {
    Object.assign(this, {x, y});
  }
}

上面方法通过Object.assign方法,将x属性和y属性添加到Point类的对象实例。

(2)为对象添加方法

Object.assign(SomeClass.prototype, {
  someMethod(arg1, arg2) {
    ···
  },
  anotherMethod() {
    ···
  }
});
// 等同于下面的写法
SomeClass.prototype.someMethod = function (arg1, arg2) {
  ···
};
SomeClass.prototype.anotherMethod = function () {
  ···
};

上面代码使用了对象属性的简洁表示法,直接将两个函数放在大括号中,再使用assign方法添加到SomeClass.prototype之中。

(3)克隆对象

function clone(origin) {
  return Object.assign({}, origin);
}

上面代码将原始对象拷贝到一个空对象,就得到了原始对象的克隆。

不过,采用这种方法克隆,只能克隆原始对象自身的值,不能克隆它继承的值。如果想要保持继承链,可以采用下面的代码。

function clone(origin) {
  let originProto = Object.getPrototypeOf(origin);
  return Object.assign(Object.create(originProto), origin);
}

(4)合并多个对象

将多个对象合并到某个对象。

const merge =
  (target, ...sources) => Object.assign(target, ...sources);

如果希望合并后返回一个新对象,可以改写上面函数,对一个空对象合并。

const merge =
  (...sources) => Object.assign({}, ...sources);

(5)为属性指定默认值

const DEFAULTS = {
  logLevel: 0,
  outputFormat: 'html'
};

function processContent(options) {
  options = Object.assign({}, DEFAULTS, options);
  console.log(options);
  // ...
}

上面代码中,DEFAULTS对象是默认值,options对象是用户提供的参数。Object.assign方法将DEFAULTS和options合并成一个新对象,如果两者有同名属性,则option的属性值会覆盖DEFAULTS的属性值。

注意,由于存在浅拷贝的问题,DEFAULTS对象和options对象的所有属性的值,最好都是简单类型,不要指向另一个对象。否则,DEFAULTS对象的该属性很可能不起作用。

const DEFAULTS = {
  url: {
    host: 'example.com',
    port: 7070
  },
};

processContent({ url: {port: 8000} })
// {
//   url: {port: 8000}
// }

上面代码的原意是将url.port改成 8000,url.host不变。实际结果却是options.url覆盖掉DEFAULTS.url,所以url.host就不存在了。

  • flat() 用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。
[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]

上面代码中,原数组的成员里面有一个数组,flat()方法将子数组的成员取出来,添加在原来的位置。

flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1。
上面代码中,flat()的参数为2,表示要“拉平”两层的嵌套数组。

如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。

[1, [2, [3]]].flat(Infinity)          // [1, 2, 3]

如果原数组有空位,flat()方法会跳过空位。

[1, 2, , 4, 5].flat()   // [1, 2, 4, 5]
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容